Skip to content

Commit

Permalink
deps: V8: cherry-pick 4b1447e4bb0e
Browse files Browse the repository at this point in the history
Original commit message:

    Improve V8 GC logic for external memory

    The logic for V8 GC normally only takes the external memory growth
    since last mark-compact into account. Unfortunately, the amount of
    external memory recorded at the end of MC is often too high. The
    reason is that it might take a while for the external memory
    associated with the GCed objects to be released (e.g. V8 itself post a
    task to release external memory for ArrayBuffer backing stores). In a
    worst case scenario GC is driven only by external memory and none of
    the external memory is released by the end of the MC. Then each MC
    will record the external memory at its highest point and the GC logic
    will allow the external memory to grow a bit higher each time which
    can lead to excessive memory use.

    This patch improves the situation a bit by calculating the growth from
    the lowest external memory seen since the last MC. That way the growth
    calculation will be offset from a level presumably closer to the
    intended one (to what it would have been if the external memory
    associated with the GCed objects was released during the MC). Now,
    this fix is not perfect because it can be thrown off by external
    memory growth occurring before the lingering memory is
    released. However, it seems to work rather well in practice (e.g. when
    playing MSE video on YT).

    Bug: v8:10185
    Change-Id: Ifcdd87eb45f3ae4a99d2aeec667c3ae4ca9a52b6
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2042711
    Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
    Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
    Reviewed-by: Jakob Gruber <jgruber@chromium.org>
    Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#66193}

Refs: v8/v8@4b1447e

PR-URL: #32885
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Ujjwal Sharma <ryzokuken@disroot.org>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com>
  • Loading branch information
addaleax authored and BethGriggs committed Apr 20, 2020
1 parent f98668a commit 122937f
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 32 deletions.
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.12',
'v8_embedder_string': '-node.13',

##### V8 defaults for Node.js #####

Expand Down
4 changes: 2 additions & 2 deletions deps/v8/include/v8-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ class Internals {
kNumIsolateDataSlots * kApiSystemPointerSize;
static const int kExternalMemoryLimitOffset =
kExternalMemoryOffset + kApiInt64Size;
static const int kExternalMemoryAtLastMarkCompactOffset =
static const int kExternalMemoryLowSinceMarkCompactOffset =
kExternalMemoryLimitOffset + kApiInt64Size;
static const int kIsolateFastCCallCallerFpOffset =
kExternalMemoryAtLastMarkCompactOffset + kApiInt64Size;
kExternalMemoryLowSinceMarkCompactOffset + kApiInt64Size;
static const int kIsolateFastCCallCallerPcOffset =
kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
static const int kIsolateStackGuardOffset =
Expand Down
27 changes: 13 additions & 14 deletions deps/v8/include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -11854,9 +11854,9 @@ int64_t Isolate::AdjustAmountOfExternalAllocatedMemory(
reinterpret_cast<uint8_t*>(this) + I::kExternalMemoryOffset);
int64_t* external_memory_limit = reinterpret_cast<int64_t*>(
reinterpret_cast<uint8_t*>(this) + I::kExternalMemoryLimitOffset);
int64_t* external_memory_at_last_mc =
int64_t* external_memory_low_since_mc =
reinterpret_cast<int64_t*>(reinterpret_cast<uint8_t*>(this) +
I::kExternalMemoryAtLastMarkCompactOffset);
I::kExternalMemoryLowSinceMarkCompactOffset);

// Embedders are weird: we see both over- and underflows here. Perform the
// addition with unsigned types to avoid undefined behavior.
Expand All @@ -11865,23 +11865,22 @@ int64_t Isolate::AdjustAmountOfExternalAllocatedMemory(
static_cast<uint64_t>(*external_memory));
*external_memory = amount;

int64_t allocation_diff_since_last_mc =
static_cast<int64_t>(static_cast<uint64_t>(*external_memory) -
static_cast<uint64_t>(*external_memory_at_last_mc));
if (amount < *external_memory_low_since_mc) {
*external_memory_low_since_mc = amount;
*external_memory_limit = amount + I::kExternalAllocationSoftLimit;
}

if (change_in_bytes <= 0) return *external_memory;

int64_t allocation_diff_since_last_mc = static_cast<int64_t>(
static_cast<uint64_t>(*external_memory) -
static_cast<uint64_t>(*external_memory_low_since_mc));
// Only check memory pressure and potentially trigger GC if the amount of
// external memory increased.
if (allocation_diff_since_last_mc > kMemoryReducerActivationLimit) {
CheckMemoryPressure();
}

if (change_in_bytes < 0) {
const int64_t lower_limit =
static_cast<int64_t>(static_cast<uint64_t>(*external_memory_limit) +
static_cast<uint64_t>(change_in_bytes));
if (lower_limit > I::kExternalAllocationSoftLimit) {
*external_memory_limit = lower_limit;
}
} else if (change_in_bytes > 0 && amount > *external_memory_limit) {
if (amount > *external_memory_limit) {
ReportExternalAllocationLimitReached();
}
return *external_memory;
Expand Down
9 changes: 5 additions & 4 deletions deps/v8/src/execution/isolate-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class IsolateData final {
V(kEmbedderDataOffset, Internals::kNumIsolateDataSlots* kSystemPointerSize) \
V(kExternalMemoryOffset, kInt64Size) \
V(kExternalMemoryLlimitOffset, kInt64Size) \
V(kExternalMemoryAtLastMarkCompactOffset, kInt64Size) \
V(kExternalMemoryLowSinceMarkCompactOffset, kInt64Size) \
V(kFastCCallCallerFPOffset, kSystemPointerSize) \
V(kFastCCallCallerPCOffset, kSystemPointerSize) \
V(kStackGuardOffset, StackGuard::kSizeInBytes) \
Expand Down Expand Up @@ -151,7 +151,7 @@ class IsolateData final {
int64_t external_memory_limit_ = kExternalAllocationSoftLimit;

// Caches the amount of external memory registered at the last MC.
int64_t external_memory_at_last_mark_compact_ = 0;
int64_t external_memory_low_since_mark_compact_ = 0;

// Stores the state of the caller for TurboAssembler::CallCFunction so that
// the sampling CPU profiler can iterate the stack during such calls. These
Expand Down Expand Up @@ -220,8 +220,9 @@ void IsolateData::AssertPredictableLayout() {
kExternalMemoryOffset);
STATIC_ASSERT(offsetof(IsolateData, external_memory_limit_) ==
kExternalMemoryLlimitOffset);
STATIC_ASSERT(offsetof(IsolateData, external_memory_at_last_mark_compact_) ==
kExternalMemoryAtLastMarkCompactOffset);
STATIC_ASSERT(
offsetof(IsolateData, external_memory_low_since_mark_compact_) ==
kExternalMemoryLowSinceMarkCompactOffset);
STATIC_ASSERT(offsetof(IsolateData, fast_c_call_caller_fp_) ==
kFastCCallCallerFPOffset);
STATIC_ASSERT(offsetof(IsolateData, fast_c_call_caller_pc_) ==
Expand Down
6 changes: 3 additions & 3 deletions deps/v8/src/execution/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2900,10 +2900,10 @@ void Isolate::CheckIsolateLayout() {
CHECK_EQ(static_cast<int>(
OFFSET_OF(Isolate, isolate_data_.external_memory_limit_)),
Internals::kExternalMemoryLimitOffset);
CHECK_EQ(Internals::kExternalMemoryAtLastMarkCompactOffset % 8, 0);
CHECK_EQ(Internals::kExternalMemoryLowSinceMarkCompactOffset % 8, 0);
CHECK_EQ(static_cast<int>(OFFSET_OF(
Isolate, isolate_data_.external_memory_at_last_mark_compact_)),
Internals::kExternalMemoryAtLastMarkCompactOffset);
Isolate, isolate_data_.external_memory_low_since_mark_compact_)),
Internals::kExternalMemoryLowSinceMarkCompactOffset);
}

void Isolate::ClearSerializerData() {
Expand Down
13 changes: 10 additions & 3 deletions deps/v8/src/heap/heap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,23 @@ int64_t Heap::external_memory() {
}

void Heap::update_external_memory(int64_t delta) {
isolate()->isolate_data()->external_memory_ += delta;
const int64_t amount = isolate()->isolate_data()->external_memory_ + delta;
isolate()->isolate_data()->external_memory_ = amount;
if (amount <
isolate()->isolate_data()->external_memory_low_since_mark_compact_) {
isolate()->isolate_data()->external_memory_low_since_mark_compact_ = amount;
isolate()->isolate_data()->external_memory_limit_ =
amount + kExternalAllocationSoftLimit;
}
}

void Heap::update_external_memory_concurrently_freed(uintptr_t freed) {
external_memory_concurrently_freed_ += freed;
}

void Heap::account_external_memory_concurrently_freed() {
isolate()->isolate_data()->external_memory_ -=
external_memory_concurrently_freed_;
update_external_memory(
-static_cast<int64_t>(external_memory_concurrently_freed_));
external_memory_concurrently_freed_ = 0;
}

Expand Down
10 changes: 5 additions & 5 deletions deps/v8/src/heap/heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1452,7 +1452,7 @@ void Heap::ReportExternalMemoryPressure() {
kGCCallbackFlagSynchronousPhantomCallbackProcessing |
kGCCallbackFlagCollectAllExternalMemory);
if (isolate()->isolate_data()->external_memory_ >
(isolate()->isolate_data()->external_memory_at_last_mark_compact_ +
(isolate()->isolate_data()->external_memory_low_since_mark_compact_ +
external_memory_hard_limit())) {
CollectAllGarbage(
kReduceMemoryFootprintMask,
Expand Down Expand Up @@ -2143,7 +2143,7 @@ void Heap::RecomputeLimits(GarbageCollector collector) {

if (collector == MARK_COMPACTOR) {
// Register the amount of external allocated memory.
isolate()->isolate_data()->external_memory_at_last_mark_compact_ =
isolate()->isolate_data()->external_memory_low_since_mark_compact_ =
isolate()->isolate_data()->external_memory_;
isolate()->isolate_data()->external_memory_limit_ =
isolate()->isolate_data()->external_memory_ +
Expand Down Expand Up @@ -4743,12 +4743,12 @@ size_t Heap::GlobalSizeOfObjects() {
uint64_t Heap::PromotedExternalMemorySize() {
IsolateData* isolate_data = isolate()->isolate_data();
if (isolate_data->external_memory_ <=
isolate_data->external_memory_at_last_mark_compact_) {
isolate_data->external_memory_low_since_mark_compact_) {
return 0;
}
return static_cast<uint64_t>(
isolate_data->external_memory_ -
isolate_data->external_memory_at_last_mark_compact_);
isolate_data->external_memory_low_since_mark_compact_);
}

bool Heap::AllocationLimitOvershotByLargeMargin() {
Expand Down Expand Up @@ -4871,7 +4871,7 @@ Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() {
double gained_since_last_gc =
PromotedSinceLastGC() +
(isolate()->isolate_data()->external_memory_ -
isolate()->isolate_data()->external_memory_at_last_mark_compact_);
isolate()->isolate_data()->external_memory_low_since_mark_compact_);
double size_before_gc =
OldGenerationObjectsAndPromotedExternalMemorySize() -
gained_since_last_gc;
Expand Down

0 comments on commit 122937f

Please sign in to comment.