Skip to content

Commit 9e3676d

Browse files
indutnyCommit bot
authored and
Commit bot
committed
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. BUG= Review URL: https://codereview.chromium.org/1316873004 Cr-Commit-Position: refs/heads/master@{#30495}
1 parent 1cd96c5 commit 9e3676d

File tree

3 files changed

+59
-98
lines changed

3 files changed

+59
-98
lines changed

src/heap/heap.cc

+54-81
Original file line numberDiff line numberDiff line change
@@ -1744,61 +1744,13 @@ void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) {
17441744
}
17451745

17461746

1747-
void Heap::RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
1748-
void* data, size_t length) {
1749-
live_buffers[data] = length;
1750-
}
1751-
1752-
1753-
void Heap::UnregisterArrayBufferHelper(
1754-
std::map<void*, size_t>& live_buffers,
1755-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
1756-
DCHECK(live_buffers.count(data) > 0);
1757-
live_buffers.erase(data);
1758-
not_yet_discovered_buffers.erase(data);
1759-
}
1760-
1761-
1762-
void Heap::RegisterLiveArrayBufferHelper(
1763-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data) {
1764-
not_yet_discovered_buffers.erase(data);
1765-
}
1766-
1767-
1768-
size_t Heap::FreeDeadArrayBuffersHelper(
1769-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1770-
std::map<void*, size_t>& not_yet_discovered_buffers) {
1771-
size_t freed_memory = 0;
1772-
for (auto buffer = not_yet_discovered_buffers.begin();
1773-
buffer != not_yet_discovered_buffers.end(); ++buffer) {
1774-
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
1775-
freed_memory += buffer->second;
1776-
live_buffers.erase(buffer->first);
1777-
}
1778-
not_yet_discovered_buffers = live_buffers;
1779-
return freed_memory;
1780-
}
1781-
1782-
1783-
void Heap::TearDownArrayBuffersHelper(
1784-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1785-
std::map<void*, size_t>& not_yet_discovered_buffers) {
1786-
for (auto buffer = live_buffers.begin(); buffer != live_buffers.end();
1787-
++buffer) {
1788-
isolate->array_buffer_allocator()->Free(buffer->first, buffer->second);
1789-
}
1790-
live_buffers.clear();
1791-
not_yet_discovered_buffers.clear();
1792-
}
1793-
1794-
17951747
void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
17961748
size_t length) {
17971749
if (!data) return;
1798-
RegisterNewArrayBufferHelper(live_array_buffers_, data, length);
17991750
if (in_new_space) {
1800-
RegisterNewArrayBufferHelper(live_array_buffers_for_scavenge_, data,
1801-
length);
1751+
live_array_buffers_for_scavenge_[data] = length;
1752+
} else {
1753+
live_array_buffers_[data] = length;
18021754
}
18031755

18041756
// We may go over the limit of externally allocated memory here. We call the
@@ -1810,54 +1762,75 @@ void Heap::RegisterNewArrayBuffer(bool in_new_space, void* data,
18101762

18111763
void Heap::UnregisterArrayBuffer(bool in_new_space, void* data) {
18121764
if (!data) return;
1813-
UnregisterArrayBufferHelper(live_array_buffers_,
1814-
not_yet_discovered_array_buffers_, data);
1815-
if (in_new_space) {
1816-
UnregisterArrayBufferHelper(live_array_buffers_for_scavenge_,
1817-
not_yet_discovered_array_buffers_for_scavenge_,
1818-
data);
1819-
}
1765+
1766+
std::map<void*, size_t>* live_buffers =
1767+
in_new_space ? &live_array_buffers_for_scavenge_ : &live_array_buffers_;
1768+
std::map<void*, size_t>* not_yet_discovered_buffers =
1769+
in_new_space ? &not_yet_discovered_array_buffers_for_scavenge_
1770+
: &not_yet_discovered_array_buffers_;
1771+
1772+
DCHECK(live_buffers->count(data) > 0);
1773+
live_buffers->erase(data);
1774+
not_yet_discovered_buffers->erase(data);
18201775
}
18211776

18221777

18231778
void Heap::RegisterLiveArrayBuffer(bool from_scavenge, void* data) {
18241779
// ArrayBuffer might be in the middle of being constructed.
18251780
if (data == undefined_value()) return;
1826-
RegisterLiveArrayBufferHelper(
1827-
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
1828-
: not_yet_discovered_array_buffers_,
1829-
data);
1781+
if (from_scavenge) {
1782+
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
1783+
} else if (!not_yet_discovered_array_buffers_.erase(data)) {
1784+
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
1785+
}
18301786
}
18311787

18321788

18331789
void Heap::FreeDeadArrayBuffers(bool from_scavenge) {
1834-
if (from_scavenge) {
1835-
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
1836-
not_yet_discovered_array_buffers_.erase(buffer.first);
1837-
live_array_buffers_.erase(buffer.first);
1838-
}
1839-
} else {
1790+
size_t freed_memory = 0;
1791+
for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) {
1792+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1793+
freed_memory += buffer.second;
1794+
live_array_buffers_for_scavenge_.erase(buffer.first);
1795+
}
1796+
1797+
if (!from_scavenge) {
18401798
for (auto& buffer : not_yet_discovered_array_buffers_) {
1841-
// Scavenge can't happend during evacuation, so we only need to update
1842-
// live_array_buffers_for_scavenge_.
1843-
// not_yet_discovered_array_buffers_for_scanvenge_ will be reset before
1844-
// the next scavenge run in PrepareArrayBufferDiscoveryInNewSpace.
1845-
live_array_buffers_for_scavenge_.erase(buffer.first);
1799+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1800+
freed_memory += buffer.second;
1801+
live_array_buffers_.erase(buffer.first);
18461802
}
18471803
}
18481804

1805+
not_yet_discovered_array_buffers_for_scavenge_ =
1806+
live_array_buffers_for_scavenge_;
1807+
if (!from_scavenge) not_yet_discovered_array_buffers_ = live_array_buffers_;
1808+
18491809
// Do not call through the api as this code is triggered while doing a GC.
1850-
amount_of_external_allocated_memory_ -= FreeDeadArrayBuffersHelper(
1851-
isolate_,
1852-
from_scavenge ? live_array_buffers_for_scavenge_ : live_array_buffers_,
1853-
from_scavenge ? not_yet_discovered_array_buffers_for_scavenge_
1854-
: not_yet_discovered_array_buffers_);
1810+
amount_of_external_allocated_memory_ -= freed_memory;
18551811
}
18561812

18571813

18581814
void Heap::TearDownArrayBuffers() {
1859-
TearDownArrayBuffersHelper(isolate_, live_array_buffers_,
1860-
not_yet_discovered_array_buffers_);
1815+
size_t freed_memory = 0;
1816+
for (auto& buffer : live_array_buffers_) {
1817+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1818+
freed_memory += buffer.second;
1819+
}
1820+
for (auto& buffer : live_array_buffers_for_scavenge_) {
1821+
isolate()->array_buffer_allocator()->Free(buffer.first, buffer.second);
1822+
freed_memory += buffer.second;
1823+
}
1824+
live_array_buffers_.clear();
1825+
live_array_buffers_for_scavenge_.clear();
1826+
not_yet_discovered_array_buffers_.clear();
1827+
not_yet_discovered_array_buffers_for_scavenge_.clear();
1828+
1829+
if (freed_memory > 0) {
1830+
reinterpret_cast<v8::Isolate*>(isolate_)
1831+
->AdjustAmountOfExternalAllocatedMemory(
1832+
-static_cast<int64_t>(freed_memory));
1833+
}
18611834
}
18621835

18631836

@@ -1875,7 +1848,7 @@ void Heap::PromoteArrayBuffer(Object* obj) {
18751848
// ArrayBuffer might be in the middle of being constructed.
18761849
if (data == undefined_value()) return;
18771850
DCHECK(live_array_buffers_for_scavenge_.count(data) > 0);
1878-
DCHECK(live_array_buffers_.count(data) > 0);
1851+
live_array_buffers_[data] = live_array_buffers_for_scavenge_[data];
18791852
live_array_buffers_for_scavenge_.erase(data);
18801853
not_yet_discovered_array_buffers_for_scavenge_.erase(data);
18811854
}

src/heap/heap.h

-15
Original file line numberDiff line numberDiff line change
@@ -1790,21 +1790,6 @@ class Heap {
17901790
// Called on heap tear-down. Frees all remaining ArrayBuffer backing stores.
17911791
void TearDownArrayBuffers();
17921792

1793-
// These correspond to the non-Helper versions.
1794-
void RegisterNewArrayBufferHelper(std::map<void*, size_t>& live_buffers,
1795-
void* data, size_t length);
1796-
void UnregisterArrayBufferHelper(
1797-
std::map<void*, size_t>& live_buffers,
1798-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
1799-
void RegisterLiveArrayBufferHelper(
1800-
std::map<void*, size_t>& not_yet_discovered_buffers, void* data);
1801-
size_t FreeDeadArrayBuffersHelper(
1802-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1803-
std::map<void*, size_t>& not_yet_discovered_buffers);
1804-
void TearDownArrayBuffersHelper(
1805-
Isolate* isolate, std::map<void*, size_t>& live_buffers,
1806-
std::map<void*, size_t>& not_yet_discovered_buffers);
1807-
18081793
// Record statistics before and after garbage collection.
18091794
void ReportStatisticsBeforeGC();
18101795
void ReportStatisticsAfterGC();

src/heap/mark-compact.cc

+5-2
Original file line numberDiff line numberDiff line change
@@ -4431,10 +4431,13 @@ void MarkCompactCollector::SweepSpaces() {
44314431
// buffer entries are already filter out. We can just release the memory.
44324432
heap()->FreeQueuedChunks();
44334433

4434-
heap()->FreeDeadArrayBuffers(false);
4435-
44364434
EvacuateNewSpaceAndCandidates();
44374435

4436+
// NOTE: ArrayBuffers must be evacuated first, before freeing them. Otherwise
4437+
// not yet discovered buffers for scavenge will have all of them, and they
4438+
// will be erroneously freed.
4439+
heap()->FreeDeadArrayBuffers(false);
4440+
44384441
// Clear the marking state of live large objects.
44394442
heap_->lo_space()->ClearMarkingStateOfLiveObjects();
44404443

0 commit comments

Comments
 (0)