Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Next Next commit
deps: V8: cherry-pick 4b1447e4bb0e
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
  • Loading branch information
addaleax authored and targos committed Apr 18, 2020
commit 8629a319f1476da385954da6f5a90be4ac9520dd
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