Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1fdec65

Browse filesBrowse files
indutnyofrobots
authored andcommitted
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. Ref: #2732 PR-URL: #3351 Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com> Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
1 parent 5cd1fd8 commit 1fdec65
Copy full SHA for 1fdec65

File tree

Expand file treeCollapse file tree

3 files changed

+57
-96
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+57
-96
lines changed
Open diff view settings
Collapse file

‎deps/v8/src/heap/heap.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/heap/heap.cc
+54-81Lines changed: 54 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,61 +1791,13 @@ void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) {
17911791
}
17921792

17931793

1794-
void Heap::RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
1795-
void* data, size_t length) {
1796-
live_buffers[data] = length;
1797-
}
1798-
1799-
1800-
void Heap::UnregisterArrayBufferHelper(
1801-
std::map<void*, size_t>& live_buffers,
1802-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
1803-
DCHECK(live_buffers.count(data) > 0);
1804-
live_buffers.erase(data);
1805-
not_yet_discovered_buffers.erase(data);
1806-
}
1807-
1808-
1809-
void Heap::RegisterLiveArrayBufferHelper(
1810-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
1811-
not_yet_discovered_buffers.erase(data);
1812-
}
1813-
1814-
1815-
size_t Heap::FreeDeadArrayBuffersHelper(
1816-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1817-
std::map<void*, size_t>& not_yet_discovered_buffers) {
1818-
size_t freed_memory = 0;
1819-
for (auto buffer = not_yet_discovered_buffers.begin();
1820-
buffer != not_yet_discovered_buffers.end(); ++buffer) {
1821-
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
1822-
freed_memory += buffer->second;
1823-
live_buffers.erase(buffer->first);
1824-
}
1825-
not_yet_discovered_buffers = live_buffers;
1826-
return freed_memory;
1827-
}
1828-
1829-
1830-
void Heap::TearDownArrayBuffersHelper(
1831-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1832-
std::map<void*, size_t>& not_yet_discovered_buffers) {
1833-
for (auto buffer = live_buffers.begin(); buffer != live_buffers.end();
1834-
++buffer) {
1835-
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
1836-
}
1837-
live_buffers.clear();
1838-
not_yet_discovered_buffers.clear();
1839-
}
1840-
1841-
18421794
void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
18431795
size_t length) {
18441796
if (!data) return;
1845-
RegisterNewArrayBufferHelper(live_array_buffers_, data, length);
18461797
if (in_new_space) {
1847-
RegisterNewArrayBufferHelper(live_array_buffers_for_scavenge_, data,
1848-
length);
1798+
live_array_buffers_for_scavenge_[data] = length;
1799+
} else {
1800+
live_array_buffers_[data] = length;
18491801
}
18501802

18511803
// We may go over the limit of externally allocated memory here. We call the
@@ -1857,54 +1809,75 @@ void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
18571809

18581810
void Heap::UnregisterArrayBuffer(bool in_new_space, void* data) {
18591811
if (!data) return;
1860-
UnregisterArrayBufferHelper(live_array_buffers_,
1861-
not_yet_discovered_array_buffers_, data);
1862-
if (in_new_space) {
1863-
UnregisterArrayBufferHelper(live_array_buffers_for_scavenge_,
1864-
not_yet_discovered_array_buffers_for_scavenge_,
1865-
data);
1866-
}
1812+
1813+
std::map<void*, size_t>* live_buffers =
1814+
in_new_space ? &live_array_buffers_for_scavenge_ : &live_array_buffers_;
1815+
std::map<void*, size_t>* not_yet_discovered_buffers =
1816+
in_new_space ? &not_yet_discovered_array_buffers_for_scavenge_
1817+
: &not_yet_discovered_array_buffers_;
1818+
1819+
DCHECK(live_buffers->count(data) > 0);
1820+
live_buffers->erase(data);
1821+
not_yet_discovered_buffers->erase(data);
18671822
}
18681823

18691824

18701825
void Heap::RegisterLiveArrayBuffer(bool from_scavenge, void* data) {
18711826
// ArrayBuffer might be in the middle of being constructed.
18721827
if (data == undefined_value()) return;
1873-
RegisterLiveArrayBufferHelper(
1874-
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
1875-
: not_yet_discovered_array_buffers_,
1876-
data);
1828+
if (from_scavenge) {
1829+
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
1830+
} else if (!not_yet_discovered_array_buffers_.erase(data)) {
1831+
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
1832+
}
18771833
}
18781834

18791835

18801836
void Heap::FreeDeadArrayBuffers(bool from_scavenge) {
1881-
if (from_scavenge) {
1882-
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
1883-
not_yet_discovered_array_buffers_.erase(buffer.first);
1884-
live_array_buffers_.erase(buffer.first);
1885-
}
1886-
} else {
1837+
size_t freed_memory = 0;
1838+
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
1839+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1840+
freed_memory += buffer.second;
1841+
live_array_buffers_for_scavenge_.erase(buffer.first);
1842+
}
1843+
1844+
if (!from_scavenge) {
18871845
for (auto& buffer : not_yet_discovered_array_buffers_) {
1888-
// Scavenge can't happend during evacuation, so we only need to update
1889-
// live_array_buffers_for_scavenge_.
1890-
// not_yet_discovered_array_buffers_for_scanvenge_ will be reset before
1891-
// the next scavenge run in PrepareArrayBufferDiscoveryInNewSpace.
1892-
live_array_buffers_for_scavenge_.erase(buffer.first);
1846+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1847+
freed_memory += buffer.second;
1848+
live_array_buffers_.erase(buffer.first);
18931849
}
18941850
}
18951851

1852+
not_yet_discovered_array_buffers_for_scavenge_ =
1853+
live_array_buffers_for_scavenge_;
1854+
if (!from_scavenge) not_yet_discovered_array_buffers_ = live_array_buffers_;
1855+
18961856
// Do not call through the api as this code is triggered while doing a GC.
1897-
amount_of_external_allocated_memory_ -= FreeDeadArrayBuffersHelper(
1898-
isolate_,
1899-
from_scavenge ? live_array_buffers_for_scavenge_ : live_array_buffers_,
1900-
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
1901-
: not_yet_discovered_array_buffers_);
1857+
amount_of_external_allocated_memory_ -= freed_memory;
19021858
}
19031859

19041860

19051861
void Heap::TearDownArrayBuffers() {
1906-
TearDownArrayBuffersHelper(isolate_, live_array_buffers_,
1907-
not_yet_discovered_array_buffers_);
1862+
size_t freed_memory = 0;
1863+
for (auto& buffer : live_array_buffers_) {
1864+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1865+
freed_memory += buffer.second;
1866+
}
1867+
for (auto& buffer : live_array_buffers_for_scavenge_) {
1868+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1869+
freed_memory += buffer.second;
1870+
}
1871+
live_array_buffers_.clear();
1872+
live_array_buffers_for_scavenge_.clear();
1873+
not_yet_discovered_array_buffers_.clear();
1874+
not_yet_discovered_array_buffers_for_scavenge_.clear();
1875+
1876+
if (freed_memory > 0) {
1877+
reinterpret_cast<v8::Isolate*>(isolate_)
1878+
->AdjustAmountOfExternalAllocatedMemory(
1879+
-static_cast<int64_t>(freed_memory));
1880+
}
19081881
}
19091882

19101883

@@ -1922,7 +1895,7 @@ void Heap::PromoteArrayBuffer(Object* obj) {
19221895
// ArrayBuffer might be in the middle of being constructed.
19231896
if (data == undefined_value()) return;
19241897
DCHECK(live_array_buffers_for_scavenge_.count(data) > 0);
1925-
DCHECK(live_array_buffers_.count(data) > 0);
1898+
live_array_buffers_[data] = live_array_buffers_for_scavenge_[data];
19261899
live_array_buffers_for_scavenge_.erase(data);
19271900
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
19281901
}
Collapse file

‎deps/v8/src/heap/heap.h‎

Copy file name to clipboardExpand all lines: deps/v8/src/heap/heap.h
-15Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,21 +2095,6 @@ class Heap {
20952095
// Called on heap tear-down. Frees all remaining ArrayBuffer backing stores.
20962096
void TearDownArrayBuffers();
20972097

2098-
// These correspond to the non-Helper versions.
2099-
void RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
2100-
void* data, size_t length);
2101-
void UnregisterArrayBufferHelper(
2102-
std::map<void*, size_t>& live_buffers,
2103-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
2104-
void RegisterLiveArrayBufferHelper(
2105-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
2106-
size_t FreeDeadArrayBuffersHelper(
2107-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
2108-
std::map<void*, size_t>& not_yet_discovered_buffers);
2109-
void TearDownArrayBuffersHelper(
2110-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
2111-
std::map<void*, size_t>& not_yet_discovered_buffers);
2112-
21132098
// Record statistics before and after garbage collection.
21142099
void ReportStatisticsBeforeGC();
21152100
void ReportStatisticsAfterGC();
Collapse file

‎deps/v8/src/heap/mark-compact.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/heap/mark-compact.cc
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4357,6 +4357,9 @@ void MarkCompactCollector::SweepSpaces() {
43574357

43584358
EvacuateNewSpaceAndCandidates();
43594359

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

43624365
// Deallocate unmarked objects and clear marked bits for marked objects.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.