Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
33787b1
readline: Added failing test for tab completion
mtharrison Aug 29, 2015
eeffc20
readline: fixed issue with tab completion
mtharrison Aug 29, 2015
a493dab
cpplint: make it possible to run outside git repo
bnoordhuis Sep 5, 2015
b3c4cec
build: make .msi install to "nodejs", not "node"
rvagg Sep 5, 2015
cdfa271
doc: update AUTHORS list
rvagg Aug 31, 2015
7ee58be
crypto: replace rwlocks with simple mutexes
bnoordhuis Sep 7, 2015
3bc7e58
child_process: use stdio.fd even if it is 0
evanlucas Sep 7, 2015
278a926
src: s/ia32/x86 for process.release.libUrl for win
rvagg Sep 5, 2015
b8341e8
deps: float node-gyp v3.0.0
rvagg Sep 5, 2015
154d3f5
build: remote commands on staging in single session
rvagg Sep 7, 2015
c7be08c
cluster: allow shared reused dgram sockets
indutny Aug 25, 2015
31450fc
deps: improve ArrayBuffer performance in v8
indutny Sep 8, 2015
22097a2
node-gyp: float 3.0.1, minor fix for download url
rvagg Sep 8, 2015
297b9ae
build: fix v8_enable_handle_zapping override
skomski Sep 7, 2015
8f87169
doc: fix comma splice in Assertion Testing doc
Trott Sep 7, 2015
380a3d8
2015-09-08, Version 4.0.0 (Stable) Release
rvagg Sep 7, 2015
f8152df
test: expect error for test_lookup_ipv6_hint on FreeBSD
Trott Sep 7, 2015
f442904
doc: describe process API for IPC
sam-github Jun 15, 2015
81a0c0b
win,msi: fix documentation shortcut url
mscdex Sep 10, 2015
d2f70fe
doc: use 3rd person singular for consistency
agcolom Sep 9, 2015
a6d674d
bindings: close after reading module struct
indutny Sep 10, 2015
acb6779
deps: cherry-pick 6da51b4 from v8's upstream
indutny Sep 10, 2015
e1fb0e8
doc: use US English for consistency
agcolom Sep 9, 2015
a1949e8
test: remove valid hostname check in test-dns.js
Trott Sep 9, 2015
2aed0aa
readline: Added failing test for tab completion
mtharrison Aug 29, 2015
e9fd78d
readline: fixed issue with tab completion
mtharrison Aug 29, 2015
ac3f7f4
readline: var => const
mtharrison Sep 11, 2015
9831203
Mergefix
mtharrison Sep 11, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
deps: improve ArrayBuffer performance in v8
This a backport of the following commits from the v8's upstream:

* 1a8c38c50513f9af07ada479629a653e1cf36ff3
* 206f12abee3f1e7eda8fc6521d48f3c319460ee1
* 9e3676da9ab1aaf7de3e8582cb3fdefcc3dbaf33

Original commit message:

    heap: make array buffer maps disjoint

    Remove intersection from the `std::map`s representing current live
    ArrayBuffers. While being simpler to understand, it poses
    significant performance issue for the active ArrayBuffer users (like
    node.js).

    Store buffers separately, and process them together during
    mark-sweep phase.

    The results of benchmarks are:

    $ ./node-slow bench && ./node-fast bench
    4997.4 ns/op
    4685.7 ns/op

    NOTE: `fast` - was a patched node.js, `slow` - unpatched node.js
    with vanilla v8.

PR-URL: #2732
Reviewed-By: Rod Vagg <rod@vagg.org>
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Roman Reiss <me@silverwind.io>
  • Loading branch information
indutny committed Sep 8, 2015
commit 31450fce7c8fe6804c84a7875d2f85a78b309125
145 changes: 59 additions & 86 deletions deps/v8/src/heap/heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1854,120 +1854,93 @@ void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) {
}


void Heap::RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
void* data, size_t length) {
live_buffers[data] = length;
}


void Heap::UnregisterArrayBufferHelper(
std::map<void*, size_t>& live_buffers,
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
DCHECK(live_buffers.count(data) > 0);
live_buffers.erase(data);
not_yet_discovered_buffers.erase(data);
}


void Heap::RegisterLiveArrayBufferHelper(
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
not_yet_discovered_buffers.erase(data);
}


size_t Heap::FreeDeadArrayBuffersHelper(
Isolate* isolate, std::map<void*, size_t>& live_buffers,
std::map<void*, size_t>& not_yet_discovered_buffers) {
size_t freed_memory = 0;
for (auto buffer = not_yet_discovered_buffers.begin();
buffer != not_yet_discovered_buffers.end(); ++buffer) {
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
freed_memory += buffer->second;
live_buffers.erase(buffer->first);
}
not_yet_discovered_buffers = live_buffers;
return freed_memory;
}


void Heap::TearDownArrayBuffersHelper(
Isolate* isolate, std::map<void*, size_t>& live_buffers,
std::map<void*, size_t>& not_yet_discovered_buffers) {
for (auto buffer = live_buffers.begin(); buffer != live_buffers.end();
++buffer) {
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
}
live_buffers.clear();
not_yet_discovered_buffers.clear();
}


void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
size_t length) {
if (!data) return;
RegisterNewArrayBufferHelper(live_array_buffers_, data, length);
if (in_new_space) {
RegisterNewArrayBufferHelper(live_array_buffers_for_scavenge_, data,
length);
live_array_buffers_for_scavenge_[data] = length;
} else {
live_array_buffers_[data] = length;
}

// We may go over the limit of externally allocated memory here. We call the
// api function to trigger a GC in this case.
reinterpret_cast<v8::Isolate*>(isolate_)
->AdjustAmountOfExternalAllocatedMemory(length);
}


void Heap::UnregisterArrayBuffer(bool in_new_space, void* data) {
if (!data) return;
UnregisterArrayBufferHelper(live_array_buffers_,
not_yet_discovered_array_buffers_, data);
if (in_new_space) {
UnregisterArrayBufferHelper(live_array_buffers_for_scavenge_,
not_yet_discovered_array_buffers_for_scavenge_,
data);
}

std::map<void*, size_t>* live_buffers =
in_new_space ? &live_array_buffers_for_scavenge_ : &live_array_buffers_;
std::map<void*, size_t>* not_yet_discovered_buffers =
in_new_space ? &not_yet_discovered_array_buffers_for_scavenge_
: &not_yet_discovered_array_buffers_;

DCHECK(live_buffers->count(data) > 0);
live_buffers->erase(data);
not_yet_discovered_buffers->erase(data);
}


void Heap::RegisterLiveArrayBuffer(bool from_scavenge, void* data) {
// ArrayBuffer might be in the middle of being constructed.
if (data == undefined_value()) return;
RegisterLiveArrayBufferHelper(
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
: not_yet_discovered_array_buffers_,
data);
if (from_scavenge) {
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
} else if (!not_yet_discovered_array_buffers_.erase(data)) {
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
}
}


void Heap::FreeDeadArrayBuffers(bool from_scavenge) {
if (from_scavenge) {
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
not_yet_discovered_array_buffers_.erase(buffer.first);
live_array_buffers_.erase(buffer.first);
}
} else {
size_t freed_memory = 0;
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
freed_memory += buffer.second;
live_array_buffers_for_scavenge_.erase(buffer.first);
}

if (!from_scavenge) {
for (auto& buffer : not_yet_discovered_array_buffers_) {
// Scavenge can't happend during evacuation, so we only need to update
// live_array_buffers_for_scavenge_.
// not_yet_discovered_array_buffers_for_scanvenge_ will be reset before
// the next scavenge run in PrepareArrayBufferDiscoveryInNewSpace.
live_array_buffers_for_scavenge_.erase(buffer.first);
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
freed_memory += buffer.second;
live_array_buffers_.erase(buffer.first);
}
}
size_t freed_memory = FreeDeadArrayBuffersHelper(
isolate_,
from_scavenge ? live_array_buffers_for_scavenge_ : live_array_buffers_,
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
: not_yet_discovered_array_buffers_);
if (freed_memory) {
reinterpret_cast<v8::Isolate*>(isolate_)
->AdjustAmountOfExternalAllocatedMemory(
-static_cast<int64_t>(freed_memory));
}

not_yet_discovered_array_buffers_for_scavenge_ =
live_array_buffers_for_scavenge_;
if (!from_scavenge) not_yet_discovered_array_buffers_ = live_array_buffers_;

// Do not call through the api as this code is triggered while doing a GC.
amount_of_external_allocated_memory_ -= freed_memory;
}


void Heap::TearDownArrayBuffers() {
TearDownArrayBuffersHelper(isolate_, live_array_buffers_,
not_yet_discovered_array_buffers_);
size_t freed_memory = 0;
for (auto& buffer : live_array_buffers_) {
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
freed_memory += buffer.second;
}
for (auto& buffer : live_array_buffers_for_scavenge_) {
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
freed_memory += buffer.second;
}
live_array_buffers_.clear();
live_array_buffers_for_scavenge_.clear();
not_yet_discovered_array_buffers_.clear();
not_yet_discovered_array_buffers_for_scavenge_.clear();

if (freed_memory > 0) {
reinterpret_cast<v8::Isolate*>(isolate_)
->AdjustAmountOfExternalAllocatedMemory(
-static_cast<int64_t>(freed_memory));
}
}


Expand All @@ -1985,7 +1958,7 @@ void Heap::PromoteArrayBuffer(Object* obj) {
// ArrayBuffer might be in the middle of being constructed.
if (data == undefined_value()) return;
DCHECK(live_array_buffers_for_scavenge_.count(data) > 0);
DCHECK(live_array_buffers_.count(data) > 0);
live_array_buffers_[data] = live_array_buffers_for_scavenge_[data];
live_array_buffers_for_scavenge_.erase(data);
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
}
Expand Down
15 changes: 0 additions & 15 deletions deps/v8/src/heap/heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -2147,21 +2147,6 @@ class Heap {
// Called on heap tear-down. Frees all remaining ArrayBuffer backing stores.
void TearDownArrayBuffers();

// These correspond to the non-Helper versions.
void RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
void* data, size_t length);
void UnregisterArrayBufferHelper(
std::map<void*, size_t>& live_buffers,
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
void RegisterLiveArrayBufferHelper(
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
size_t FreeDeadArrayBuffersHelper(
Isolate* isolate, std::map<void*, size_t>& live_buffers,
std::map<void*, size_t>& not_yet_discovered_buffers);
void TearDownArrayBuffersHelper(
Isolate* isolate, std::map<void*, size_t>& live_buffers,
std::map<void*, size_t>& not_yet_discovered_buffers);

// Record statistics before and after garbage collection.
void ReportStatisticsBeforeGC();
void ReportStatisticsAfterGC();
Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/heap/mark-compact.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4310,6 +4310,9 @@ void MarkCompactCollector::SweepSpaces() {

EvacuateNewSpaceAndCandidates();

// NOTE: ArrayBuffers must be evacuated first, before freeing them. Otherwise
// not yet discovered buffers for scavenge will have all of them, and they
// will be erroneously freed.
heap()->FreeDeadArrayBuffers(false);

// ClearNonLiveReferences depends on precise sweeping of map space to
Expand Down