• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   size_t new_space_size = 0;
103   size_t new_space_available = 0;
104   size_t new_space_committed_memory = 0;
105 
106   if (heap->new_space()) {
107     new_space_size = heap->new_space()->Size();
108     new_space_available = heap->new_space()->Available();
109     new_space_committed_memory = heap->new_space()->CommittedMemory();
110   }
111 
112   const StatisticNumber numbers[] = {
113       {heap->memory_allocator()->Size(), "total_committed_bytes"},
114       {new_space_size, "new_space_live_bytes"},
115       {new_space_available, "new_space_available_bytes"},
116       {new_space_committed_memory, "new_space_commited_bytes"},
117       {heap->old_space()->Size(), "old_space_live_bytes"},
118       {heap->old_space()->Available(), "old_space_available_bytes"},
119       {heap->old_space()->CommittedMemory(), "old_space_commited_bytes"},
120       {heap->code_space()->Size(), "code_space_live_bytes"},
121       {heap->code_space()->Available(), "code_space_available_bytes"},
122       {heap->code_space()->CommittedMemory(), "code_space_commited_bytes"},
123       {heap->lo_space()->Size(), "lo_space_live_bytes"},
124       {heap->lo_space()->Available(), "lo_space_available_bytes"},
125       {heap->lo_space()->CommittedMemory(), "lo_space_commited_bytes"},
126       {heap->code_lo_space()->Size(), "code_lo_space_live_bytes"},
127       {heap->code_lo_space()->Available(), "code_lo_space_available_bytes"},
128       {heap->code_lo_space()->CommittedMemory(),
129        "code_lo_space_commited_bytes"},
130   };
131 
132   for (size_t i = 0; i < arraysize(numbers); i++) {
133     AddNumber(args.GetIsolate(), result, numbers[i].number, numbers[i].name);
134   }
135 
136   AddNumber64(args.GetIsolate(), result, heap->external_memory(),
137               "amount_of_external_allocated_memory");
138 
139   int reloc_info_total = 0;
140   int source_position_table_total = 0;
141   {
142     HeapObjectIterator iterator(
143         reinterpret_cast<Isolate*>(args.GetIsolate())->heap());
144     DCHECK(!AllowGarbageCollection::IsAllowed());
145     for (HeapObject obj = iterator.Next(); !obj.is_null();
146          obj = iterator.Next()) {
147       Object maybe_source_positions;
148       if (obj.IsCode()) {
149         Code code = Code::cast(obj);
150         reloc_info_total += code.relocation_info().Size();
151         // Baseline code doesn't have source positions since it uses
152         // interpreter code positions.
153         if (code.kind() == CodeKind::BASELINE) continue;
154         maybe_source_positions = code.source_position_table();
155       } else if (obj.IsBytecodeArray()) {
156         maybe_source_positions =
157             BytecodeArray::cast(obj).source_position_table(kAcquireLoad);
158       } else {
159         continue;
160       }
161       if (!maybe_source_positions.IsByteArray()) continue;
162       ByteArray source_positions = ByteArray::cast(maybe_source_positions);
163       if (source_positions.length() == 0) continue;
164       source_position_table_total += source_positions.Size();
165     }
166   }
167 
168   AddNumber(args.GetIsolate(), result, reloc_info_total,
169             "reloc_info_total_size");
170   AddNumber(args.GetIsolate(), result, source_position_table_total,
171             "source_position_table_total_size");
172   args.GetReturnValue().Set(result);
173 }
174 
175 }  // namespace internal
176 }  // namespace v8
177