Skip to content

Commit 5435cf2

Browse files
vkurchatkinbnoordhuis
authored andcommitted
v8: optimize getHeapStatistics
Since setting object properties in C++ can be slow, pass data to JS using preallocated smalloc buffer and create object in JS instead. PR-URL: #469 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
1 parent 5d01463 commit 5435cf2

File tree

4 files changed

+73
-20
lines changed

4 files changed

+73
-20
lines changed

lib/v8.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,29 @@
1515
'use strict';
1616

1717
var v8binding = process.binding('v8');
18-
exports.getHeapStatistics = v8binding.getHeapStatistics;
18+
var smalloc = require('smalloc');
19+
20+
var heapStatisticsBuffer = smalloc.alloc(v8binding.kHeapStatisticsBufferLength,
21+
v8binding.kHeapStatisticsBufferType);
22+
23+
var kTotalHeapSizeIndex = v8binding.kTotalHeapSizeIndex;
24+
var kTotalHeapSizeExecutableIndex = v8binding.kTotalHeapSizeExecutableIndex;
25+
var kTotalPhysicalSizeIndex = v8binding.kTotalPhysicalSizeIndex;
26+
var kUsedHeapSizeIndex = v8binding.kUsedHeapSizeIndex;
27+
var kHeapSizeLimitIndex = v8binding.kHeapSizeLimitIndex;
28+
29+
exports.getHeapStatistics = function() {
30+
var buffer = heapStatisticsBuffer;
31+
32+
v8binding.getHeapStatistics(buffer);
33+
34+
return {
35+
'total_heap_size': buffer[kTotalHeapSizeIndex],
36+
'total_heap_size_executable': buffer[kTotalHeapSizeExecutableIndex],
37+
'total_physical_size': buffer[kTotalPhysicalSizeIndex],
38+
'used_heap_size': buffer[kUsedHeapSizeIndex],
39+
'heap_size_limit': buffer[kHeapSizeLimitIndex]
40+
};
41+
};
42+
1943
exports.setFlagsFromString = v8binding.setFlagsFromString;

src/env.h

-5
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ namespace node {
9292
V(fsevent_string, "FSEvent") \
9393
V(gid_string, "gid") \
9494
V(handle_string, "handle") \
95-
V(heap_size_limit_string, "heap_size_limit") \
9695
V(heap_total_string, "heapTotal") \
9796
V(heap_used_string, "heapUsed") \
9897
V(hostmaster_string, "hostmaster") \
@@ -198,13 +197,9 @@ namespace node {
198197
V(tls_sni_string, "tls_sni") \
199198
V(tls_string, "tls") \
200199
V(tls_ticket_string, "tlsTicket") \
201-
V(total_heap_size_executable_string, "total_heap_size_executable") \
202-
V(total_heap_size_string, "total_heap_size") \
203-
V(total_physical_size_string, "total_physical_size") \
204200
V(type_string, "type") \
205201
V(uid_string, "uid") \
206202
V(unknown_string, "<unknown>") \
207-
V(used_heap_size_string, "used_heap_size") \
208203
V(user_string, "user") \
209204
V(uv_string, "uv") \
210205
V(valid_from_string, "valid_from") \

src/node_v8.cc

+47-13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace node {
99

1010
using v8::Context;
11+
using v8::ExternalArrayType;
1112
using v8::Function;
1213
using v8::FunctionCallbackInfo;
1314
using v8::Handle;
@@ -20,25 +21,41 @@ using v8::Uint32;
2021
using v8::V8;
2122
using v8::Value;
2223

24+
#define HEAP_STATISTICS_PROPERTIES(V) \
25+
V(0, total_heap_size, kTotalHeapSizeIndex) \
26+
V(1, total_heap_size_executable, kTotalHeapSizeExecutableIndex) \
27+
V(2, total_physical_size, kTotalPhysicalSizeIndex) \
28+
V(3, used_heap_size, kUsedHeapSizeIndex) \
29+
V(4, heap_size_limit, kHeapSizeLimitIndex)
30+
31+
#define V(a, b, c) +1
32+
static const size_t kHeapStatisticsBufferLength = HEAP_STATISTICS_PROPERTIES(V);
33+
#undef V
34+
35+
static const ExternalArrayType kHeapStatisticsBufferType =
36+
v8::kExternalUint32Array;
2337

2438
void GetHeapStatistics(const FunctionCallbackInfo<Value>& args) {
25-
Environment* env = Environment::GetCurrent(args);
39+
CHECK(args.Length() == 1 && args[0]->IsObject());
40+
2641
Isolate* isolate = args.GetIsolate();
2742
HeapStatistics s;
2843
isolate->GetHeapStatistics(&s);
29-
Local<Object> info = Object::New(isolate);
30-
// TODO(trevnorris): Setting many object properties in C++ is a significant
31-
// performance hit. Redo this to pass the results to JS and create/set the
32-
// properties there.
33-
#define V(name) \
34-
info->Set(env->name ## _string(), Uint32::NewFromUnsigned(isolate, s.name()))
35-
V(total_heap_size);
36-
V(total_heap_size_executable);
37-
V(total_physical_size);
38-
V(used_heap_size);
39-
V(heap_size_limit);
44+
Local<Object> obj = args[0].As<Object>();
45+
uint32_t* data =
46+
static_cast<uint32_t*>(obj->GetIndexedPropertiesExternalArrayData());
47+
48+
CHECK_NE(data, nullptr);
49+
ASSERT_EQ(obj->GetIndexedPropertiesExternalArrayDataType(),
50+
kHeapStatisticsBufferType);
51+
ASSERT_EQ(obj->GetIndexedPropertiesExternalArrayDataLength(),
52+
kHeapStatisticsBufferLength);
53+
54+
#define V(i, name, _) \
55+
data[i] = static_cast<uint32_t>(s.name());
56+
57+
HEAP_STATISTICS_PROPERTIES(V)
4058
#undef V
41-
args.GetReturnValue().Set(info);
4259
}
4360

4461

@@ -54,6 +71,23 @@ void InitializeV8Bindings(Handle<Object> target,
5471
Environment* env = Environment::GetCurrent(context);
5572
env->SetMethod(target, "getHeapStatistics", GetHeapStatistics);
5673
env->SetMethod(target, "setFlagsFromString", SetFlagsFromString);
74+
75+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
76+
"kHeapStatisticsBufferLength"),
77+
Uint32::NewFromUnsigned(env->isolate(),
78+
kHeapStatisticsBufferLength));
79+
80+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
81+
"kHeapStatisticsBufferType"),
82+
Uint32::NewFromUnsigned(env->isolate(),
83+
kHeapStatisticsBufferType));
84+
85+
#define V(i, _, name) \
86+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
87+
Uint32::NewFromUnsigned(env->isolate(), i));
88+
89+
HEAP_STATISTICS_PROPERTIES(V)
90+
#undef V
5791
}
5892

5993
} // namespace node

src/smalloc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ NODE_EXTERN size_t ExternalArraySize(enum v8::ExternalArrayType type);
4949
* v8::kExternalFloatArray);
5050
* v8::Local<v8::Object> obj = v8::Object::New();
5151
* char* data = static_cast<char*>(malloc(byte_length * array_length));
52-
* node::smalloc::Alloc(obj, data, byte_length, v8::kExternalFloatArray);
52+
* node::smalloc::Alloc(env, obj, data, byte_length, v8::kExternalFloatArray);
5353
* obj->Set(v8::String::NewFromUtf8("length"),
5454
* v8::Integer::NewFromUnsigned(array_length));
5555
* \code

0 commit comments

Comments
 (0)