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/execution/isolate.h"
8 #include "src/heap/heap-inl.h" // crbug.com/v8/8499
9 #include "src/logging/counters.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_EQ(strcmp(*v8::String::Utf8Value(isolate, 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
31 ->Set(isolate->GetCurrentContext(),
32 v8::String::NewFromUtf8(isolate, name).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).ToLocalChecked(),
43 v8::Number::New(isolate, value))
44 .FromJust();
45 }
46
47
AddNumber64(v8::Isolate * isolate,v8::Local<v8::Object> object,int64_t value,const char * name)48 static void AddNumber64(v8::Isolate* isolate,
49 v8::Local<v8::Object> object,
50 int64_t value,
51 const char* name) {
52 object
53 ->Set(isolate->GetCurrentContext(),
54 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(),
55 v8::Number::New(isolate, static_cast<double>(value)))
56 .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() && args[0]->BooleanValue(args.GetIsolate())) {
67 heap->CollectAllGarbage(Heap::kNoGCFlags,
68 GarbageCollectionReason::kCountersExtension);
69 }
70 }
71
72 Counters* counters = isolate->counters();
73 v8::Local<v8::Object> result = v8::Object::New(args.GetIsolate());
74
75 struct StatisticsCounter {
76 v8::internal::StatsCounter* counter;
77 const char* name;
78 };
79 // clang-format off
80 const StatisticsCounter counter_list[] = {
81 #define ADD_COUNTER(name, caption) {counters->name(), #name},
82 STATS_COUNTER_LIST_1(ADD_COUNTER)
83 STATS_COUNTER_LIST_2(ADD_COUNTER)
84 STATS_COUNTER_NATIVE_CODE_LIST(ADD_COUNTER)
85 #undef ADD_COUNTER
86 }; // End counter_list array.
87 // clang-format on
88
89 for (size_t i = 0; i < arraysize(counter_list); i++) {
90 AddCounter(args.GetIsolate(), result, counter_list[i].counter,
91 counter_list[i].name);
92 }
93
94 struct StatisticNumber {
95 size_t number;
96 const char* name;
97 };
98
99 const StatisticNumber numbers[] = {
100 {heap->memory_allocator()->Size(), "total_committed_bytes"},
101 {heap->new_space()->Size(), "new_space_live_bytes"},
102 {heap->new_space()->Available(), "new_space_available_bytes"},
103 {heap->new_space()->CommittedMemory(), "new_space_commited_bytes"},
104 {heap->old_space()->Size(), "old_space_live_bytes"},
105 {heap->old_space()->Available(), "old_space_available_bytes"},
106 {heap->old_space()->CommittedMemory(), "old_space_commited_bytes"},
107 {heap->code_space()->Size(), "code_space_live_bytes"},
108 {heap->code_space()->Available(), "code_space_available_bytes"},
109 {heap->code_space()->CommittedMemory(), "code_space_commited_bytes"},
110 {heap->lo_space()->Size(), "lo_space_live_bytes"},
111 {heap->lo_space()->Available(), "lo_space_available_bytes"},
112 {heap->lo_space()->CommittedMemory(), "lo_space_commited_bytes"},
113 {heap->code_lo_space()->Size(), "code_lo_space_live_bytes"},
114 {heap->code_lo_space()->Available(), "code_lo_space_available_bytes"},
115 {heap->code_lo_space()->CommittedMemory(),
116 "code_lo_space_commited_bytes"},
117 };
118
119 for (size_t i = 0; i < arraysize(numbers); i++) {
120 AddNumber(args.GetIsolate(), result, numbers[i].number, numbers[i].name);
121 }
122
123 AddNumber64(args.GetIsolate(), result, heap->external_memory(),
124 "amount_of_external_allocated_memory");
125 args.GetReturnValue().Set(result);
126
127 HeapObjectIterator iterator(
128 reinterpret_cast<Isolate*>(args.GetIsolate())->heap());
129 int reloc_info_total = 0;
130 int source_position_table_total = 0;
131 for (HeapObject obj = iterator.Next(); !obj.is_null();
132 obj = iterator.Next()) {
133 if (obj.IsCode()) {
134 Code code = Code::cast(obj);
135 reloc_info_total += code.relocation_info().Size();
136 ByteArray source_position_table = code.SourcePositionTable();
137 if (source_position_table.length() > 0) {
138 source_position_table_total += code.SourcePositionTable().Size();
139 }
140 } else if (obj.IsBytecodeArray()) {
141 source_position_table_total +=
142 BytecodeArray::cast(obj).SourcePositionTable().Size();
143 }
144 }
145
146 AddNumber(args.GetIsolate(), result, reloc_info_total,
147 "reloc_info_total_size");
148 AddNumber(args.GetIsolate(), result, source_position_table_total,
149 "source_position_table_total_size");
150 }
151
152 } // namespace internal
153 } // namespace v8
154