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 "include/v8-template.h"
8 #include "src/common/assert-scope.h"
9 #include "src/execution/isolate.h"
10 #include "src/heap/heap-inl.h" // crbug.com/v8/8499
11 #include "src/logging/counters.h"
12 #include "src/roots/roots.h"
13
14 namespace v8 {
15 namespace internal {
16
17 const char* const StatisticsExtension::kSource =
18 "native function getV8Statistics();";
19
20
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Local<v8::String> str)21 v8::Local<v8::FunctionTemplate> StatisticsExtension::GetNativeFunctionTemplate(
22 v8::Isolate* isolate, v8::Local<v8::String> str) {
23 DCHECK_EQ(strcmp(*v8::String::Utf8Value(isolate, str), "getV8Statistics"), 0);
24 return v8::FunctionTemplate::New(isolate, StatisticsExtension::GetCounters);
25 }
26
27
AddCounter(v8::Isolate * isolate,v8::Local<v8::Object> object,StatsCounter * counter,const char * name)28 static void AddCounter(v8::Isolate* isolate,
29 v8::Local<v8::Object> object,
30 StatsCounter* counter,
31 const char* name) {
32 if (counter->Enabled()) {
33 object
34 ->Set(isolate->GetCurrentContext(),
35 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(),
36 v8::Number::New(isolate, *counter->GetInternalPointer()))
37 .FromJust();
38 }
39 }
40
AddNumber(v8::Isolate * isolate,v8::Local<v8::Object> object,double value,const char * name)41 static void AddNumber(v8::Isolate* isolate, v8::Local<v8::Object> object,
42 double value, const char* name) {
43 object
44 ->Set(isolate->GetCurrentContext(),
45 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(),
46 v8::Number::New(isolate, value))
47 .FromJust();
48 }
49
50
AddNumber64(v8::Isolate * isolate,v8::Local<v8::Object> object,int64_t value,const char * name)51 static void AddNumber64(v8::Isolate* isolate,
52 v8::Local<v8::Object> object,
53 int64_t value,
54 const char* name) {
55 object
56 ->Set(isolate->GetCurrentContext(),
57 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(),
58 v8::Number::New(isolate, static_cast<double>(value)))
59 .FromJust();
60 }
61
62
GetCounters(const v8::FunctionCallbackInfo<v8::Value> & args)63 void StatisticsExtension::GetCounters(
64 const v8::FunctionCallbackInfo<v8::Value>& args) {
65 Isolate* isolate = reinterpret_cast<Isolate*>(args.GetIsolate());
66 Heap* heap = isolate->heap();
67
68 if (args.Length() > 0) { // GC if first argument evaluates to true.
69 if (args[0]->IsBoolean() && args[0]->BooleanValue(args.GetIsolate())) {
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 // clang-format off
83 const StatisticsCounter counter_list[] = {
84 #define ADD_COUNTER(name, caption) {counters->name(), #name},
85 STATS_COUNTER_LIST_1(ADD_COUNTER)
86 STATS_COUNTER_LIST_2(ADD_COUNTER)
87 STATS_COUNTER_NATIVE_CODE_LIST(ADD_COUNTER)
88 #undef ADD_COUNTER
89 }; // End counter_list array.
90 // clang-format on
91
92 for (size_t i = 0; i < arraysize(counter_list); i++) {
93 AddCounter(args.GetIsolate(), result, counter_list[i].counter,
94 counter_list[i].name);
95 }
96
97 struct StatisticNumber {
98 size_t number;
99 const char* name;
100 };
101
102 const StatisticNumber numbers[] = {
103 {heap->memory_allocator()->Size(), "total_committed_bytes"},
104 {heap->new_space()->Size(), "new_space_live_bytes"},
105 {heap->new_space()->Available(), "new_space_available_bytes"},
106 {heap->new_space()->CommittedMemory(), "new_space_commited_bytes"},
107 {heap->old_space()->Size(), "old_space_live_bytes"},
108 {heap->old_space()->Available(), "old_space_available_bytes"},
109 {heap->old_space()->CommittedMemory(), "old_space_commited_bytes"},
110 {heap->code_space()->Size(), "code_space_live_bytes"},
111 {heap->code_space()->Available(), "code_space_available_bytes"},
112 {heap->code_space()->CommittedMemory(), "code_space_commited_bytes"},
113 {heap->lo_space()->Size(), "lo_space_live_bytes"},
114 {heap->lo_space()->Available(), "lo_space_available_bytes"},
115 {heap->lo_space()->CommittedMemory(), "lo_space_commited_bytes"},
116 {heap->code_lo_space()->Size(), "code_lo_space_live_bytes"},
117 {heap->code_lo_space()->Available(), "code_lo_space_available_bytes"},
118 {heap->code_lo_space()->CommittedMemory(),
119 "code_lo_space_commited_bytes"},
120 };
121
122 for (size_t i = 0; i < arraysize(numbers); i++) {
123 AddNumber(args.GetIsolate(), result, numbers[i].number, numbers[i].name);
124 }
125
126 AddNumber64(args.GetIsolate(), result, heap->external_memory(),
127 "amount_of_external_allocated_memory");
128 args.GetReturnValue().Set(result);
129
130 DisallowGarbageCollection no_gc;
131 HeapObjectIterator iterator(
132 reinterpret_cast<Isolate*>(args.GetIsolate())->heap());
133 int reloc_info_total = 0;
134 int source_position_table_total = 0;
135 for (HeapObject obj = iterator.Next(); !obj.is_null();
136 obj = iterator.Next()) {
137 Object maybe_source_positions;
138 if (obj.IsCode()) {
139 Code code = Code::cast(obj);
140 reloc_info_total += code.relocation_info().Size();
141 maybe_source_positions = code.source_position_table();
142 } else if (obj.IsBytecodeArray()) {
143 maybe_source_positions =
144 BytecodeArray::cast(obj).source_position_table(kAcquireLoad);
145 } else {
146 continue;
147 }
148 if (!maybe_source_positions.IsByteArray()) continue;
149 ByteArray source_positions = ByteArray::cast(maybe_source_positions);
150 if (source_positions.length() == 0) continue;
151 source_position_table_total += source_positions.Size();
152 }
153
154 AddNumber(args.GetIsolate(), result, reloc_info_total,
155 "reloc_info_total_size");
156 AddNumber(args.GetIsolate(), result, source_position_table_total,
157 "source_position_table_total_size");
158 }
159
160 } // namespace internal
161 } // namespace v8
162