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 31450fc

Browse filesBrowse files
committed
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>
1 parent c7be08c commit 31450fc
Copy full SHA for 31450fc

File tree

Expand file treeCollapse file tree

3 files changed

+62
-101
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+62
-101
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
+59-86Lines changed: 59 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,120 +1854,93 @@ void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) {
18541854
}
18551855

18561856

1857-
void Heap::RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
1858-
void* data, size_t length) {
1859-
live_buffers[data] = length;
1860-
}
1861-
1862-
1863-
void Heap::UnregisterArrayBufferHelper(
1864-
std::map<void*, size_t>& live_buffers,
1865-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
1866-
DCHECK(live_buffers.count(data) > 0);
1867-
live_buffers.erase(data);
1868-
not_yet_discovered_buffers.erase(data);
1869-
}
1870-
1871-
1872-
void Heap::RegisterLiveArrayBufferHelper(
1873-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
1874-
not_yet_discovered_buffers.erase(data);
1875-
}
1876-
1877-
1878-
size_t Heap::FreeDeadArrayBuffersHelper(
1879-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1880-
std::map<void*, size_t>& not_yet_discovered_buffers) {
1881-
size_t freed_memory = 0;
1882-
for (auto buffer = not_yet_discovered_buffers.begin();
1883-
buffer != not_yet_discovered_buffers.end(); ++buffer) {
1884-
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
1885-
freed_memory += buffer->second;
1886-
live_buffers.erase(buffer->first);
1887-
}
1888-
not_yet_discovered_buffers = live_buffers;
1889-
return freed_memory;
1890-
}
1891-
1892-
1893-
void Heap::TearDownArrayBuffersHelper(
1894-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1895-
std::map<void*, size_t>& not_yet_discovered_buffers) {
1896-
for (auto buffer = live_buffers.begin(); buffer != live_buffers.end();
1897-
++buffer) {
1898-
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
1899-
}
1900-
live_buffers.clear();
1901-
not_yet_discovered_buffers.clear();
1902-
}
1903-
1904-
19051857
void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
19061858
size_t length) {
19071859
if (!data) return;
1908-
RegisterNewArrayBufferHelper(live_array_buffers_, data, length);
19091860
if (in_new_space) {
1910-
RegisterNewArrayBufferHelper(live_array_buffers_for_scavenge_, data,
1911-
length);
1861+
live_array_buffers_for_scavenge_[data] = length;
1862+
} else {
1863+
live_array_buffers_[data] = length;
19121864
}
1865+
1866+
// We may go over the limit of externally allocated memory here. We call the
1867+
// api function to trigger a GC in this case.
19131868
reinterpret_cast<v8::Isolate*>(isolate_)
19141869
->AdjustAmountOfExternalAllocatedMemory(length);
19151870
}
19161871

19171872

19181873
void Heap::UnregisterArrayBuffer(bool in_new_space, void* data) {
19191874
if (!data) return;
1920-
UnregisterArrayBufferHelper(live_array_buffers_,
1921-
not_yet_discovered_array_buffers_, data);
1922-
if (in_new_space) {
1923-
UnregisterArrayBufferHelper(live_array_buffers_for_scavenge_,
1924-
not_yet_discovered_array_buffers_for_scavenge_,
1925-
data);
1926-
}
1875+
1876+
std::map<void*, size_t>* live_buffers =
1877+
in_new_space ? &live_array_buffers_for_scavenge_ : &live_array_buffers_;
1878+
std::map<void*, size_t>* not_yet_discovered_buffers =
1879+
in_new_space ? &not_yet_discovered_array_buffers_for_scavenge_
1880+
: &not_yet_discovered_array_buffers_;
1881+
1882+
DCHECK(live_buffers->count(data) > 0);
1883+
live_buffers->erase(data);
1884+
not_yet_discovered_buffers->erase(data);
19271885
}
19281886

19291887

19301888
void Heap::RegisterLiveArrayBuffer(bool from_scavenge, void* data) {
19311889
// ArrayBuffer might be in the middle of being constructed.
19321890
if (data == undefined_value()) return;
1933-
RegisterLiveArrayBufferHelper(
1934-
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
1935-
: not_yet_discovered_array_buffers_,
1936-
data);
1891+
if (from_scavenge) {
1892+
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
1893+
} else if (!not_yet_discovered_array_buffers_.erase(data)) {
1894+
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
1895+
}
19371896
}
19381897

19391898

19401899
void Heap::FreeDeadArrayBuffers(bool from_scavenge) {
1941-
if (from_scavenge) {
1942-
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
1943-
not_yet_discovered_array_buffers_.erase(buffer.first);
1944-
live_array_buffers_.erase(buffer.first);
1945-
}
1946-
} else {
1900+
size_t freed_memory = 0;
1901+
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
1902+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1903+
freed_memory += buffer.second;
1904+
live_array_buffers_for_scavenge_.erase(buffer.first);
1905+
}
1906+
1907+
if (!from_scavenge) {
19471908
for (auto& buffer : not_yet_discovered_array_buffers_) {
1948-
// Scavenge can't happend during evacuation, so we only need to update
1949-
// live_array_buffers_for_scavenge_.
1950-
// not_yet_discovered_array_buffers_for_scanvenge_ will be reset before
1951-
// the next scavenge run in PrepareArrayBufferDiscoveryInNewSpace.
1952-
live_array_buffers_for_scavenge_.erase(buffer.first);
1909+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1910+
freed_memory += buffer.second;
1911+
live_array_buffers_.erase(buffer.first);
19531912
}
19541913
}
1955-
size_t freed_memory = FreeDeadArrayBuffersHelper(
1956-
isolate_,
1957-
from_scavenge ? live_array_buffers_for_scavenge_ : live_array_buffers_,
1958-
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
1959-
: not_yet_discovered_array_buffers_);
1960-
if (freed_memory) {
1961-
reinterpret_cast<v8::Isolate*>(isolate_)
1962-
->AdjustAmountOfExternalAllocatedMemory(
1963-
-static_cast<int64_t>(freed_memory));
1964-
}
1914+
1915+
not_yet_discovered_array_buffers_for_scavenge_ =
1916+
live_array_buffers_for_scavenge_;
1917+
if (!from_scavenge) not_yet_discovered_array_buffers_ = live_array_buffers_;
1918+
1919+
// Do not call through the api as this code is triggered while doing a GC.
1920+
amount_of_external_allocated_memory_ -= freed_memory;
19651921
}
19661922

19671923

19681924
void Heap::TearDownArrayBuffers() {
1969-
TearDownArrayBuffersHelper(isolate_, live_array_buffers_,
1970-
not_yet_discovered_array_buffers_);
1925+
size_t freed_memory = 0;
1926+
for (auto& buffer : live_array_buffers_) {
1927+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1928+
freed_memory += buffer.second;
1929+
}
1930+
for (auto& buffer : live_array_buffers_for_scavenge_) {
1931+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1932+
freed_memory += buffer.second;
1933+
}
1934+
live_array_buffers_.clear();
1935+
live_array_buffers_for_scavenge_.clear();
1936+
not_yet_discovered_array_buffers_.clear();
1937+
not_yet_discovered_array_buffers_for_scavenge_.clear();
1938+
1939+
if (freed_memory > 0) {
1940+
reinterpret_cast<v8::Isolate*>(isolate_)
1941+
->AdjustAmountOfExternalAllocatedMemory(
1942+
-static_cast<int64_t>(freed_memory));
1943+
}
19711944
}
19721945

19731946

@@ -1985,7 +1958,7 @@ void Heap::PromoteArrayBuffer(Object* obj) {
19851958
// ArrayBuffer might be in the middle of being constructed.
19861959
if (data == undefined_value()) return;
19871960
DCHECK(live_array_buffers_for_scavenge_.count(data) > 0);
1988-
DCHECK(live_array_buffers_.count(data) > 0);
1961+
live_array_buffers_[data] = live_array_buffers_for_scavenge_[data];
19891962
live_array_buffers_for_scavenge_.erase(data);
19901963
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
19911964
}
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
@@ -2147,21 +2147,6 @@ class Heap {
21472147
// Called on heap tear-down. Frees all remaining ArrayBuffer backing stores.
21482148
void TearDownArrayBuffers();
21492149

2150-
// These correspond to the non-Helper versions.
2151-
void RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
2152-
void* data, size_t length);
2153-
void UnregisterArrayBufferHelper(
2154-
std::map<void*, size_t>& live_buffers,
2155-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
2156-
void RegisterLiveArrayBufferHelper(
2157-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
2158-
size_t FreeDeadArrayBuffersHelper(
2159-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
2160-
std::map<void*, size_t>& not_yet_discovered_buffers);
2161-
void TearDownArrayBuffersHelper(
2162-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
2163-
std::map<void*, size_t>& not_yet_discovered_buffers);
2164-
21652150
// Record statistics before and after garbage collection.
21662151
void ReportStatisticsBeforeGC();
21672152
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
@@ -4310,6 +4310,9 @@ void MarkCompactCollector::SweepSpaces() {
43104310

43114311
EvacuateNewSpaceAndCandidates();
43124312

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

43154318
// ClearNonLiveReferences depends on precise sweeping of map space to

0 commit comments

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