Commit 3e919578 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] Randomize the timeout for forcing GC in the MeasureMemory API

Chrome may send memory measurement requests to multiple renderer
processes at the same time. This may lead to multiple GC happening at
the same time if the processes are idle. Randomization spreads out
the GCs over time to reduce the load on the system.

Bug: chromium:1049093
Change-Id: I5aa67fb07f8a55d0ba769bf823168b35cb3c23cb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2208861
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68472}
parent ad913fe4
......@@ -165,7 +165,12 @@ void MeasureMemoryDelegate::MeasurementComplete(
JSPromise::Resolve(promise_, result).ToHandleChecked();
}
MemoryMeasurement::MemoryMeasurement(Isolate* isolate) : isolate_(isolate) {}
MemoryMeasurement::MemoryMeasurement(Isolate* isolate)
: isolate_(isolate), random_number_generator_() {
if (FLAG_random_seed) {
random_number_generator_.SetSeed(FLAG_random_seed);
}
}
bool MemoryMeasurement::EnqueueRequest(
std::unique_ptr<v8::MeasureMemoryDelegate> delegate,
......@@ -286,10 +291,15 @@ void MemoryMeasurement::ScheduleGCTask(v8::MeasureMemoryExecution execution) {
if (execution == v8::MeasureMemoryExecution::kEager) {
taskrunner->PostTask(std::move(task));
} else {
taskrunner->PostDelayedTask(std::move(task), kGCTaskDelayInSeconds);
taskrunner->PostDelayedTask(std::move(task), NextGCTaskDelayInSeconds());
}
}
int MemoryMeasurement::NextGCTaskDelayInSeconds() {
return kGCTaskDelayInSeconds +
random_number_generator_.NextInt(kGCTaskDelayInSeconds);
}
void MemoryMeasurement::ReportResults() {
while (!done_.empty()) {
Request request = std::move(done_.front());
......
......@@ -9,6 +9,7 @@
#include <unordered_map>
#include "src/base/platform/elapsed-timer.h"
#include "src/base/utils/random-number-generator.h"
#include "src/common/globals.h"
#include "src/objects/contexts.h"
#include "src/objects/map.h"
......@@ -49,6 +50,7 @@ class MemoryMeasurement {
bool IsGCTaskPending(v8::MeasureMemoryExecution execution);
void SetGCTaskPending(v8::MeasureMemoryExecution execution);
void SetGCTaskDone(v8::MeasureMemoryExecution execution);
int NextGCTaskDelayInSeconds();
std::list<Request> received_;
std::list<Request> processing_;
......@@ -57,6 +59,7 @@ class MemoryMeasurement {
bool reporting_task_pending_ = false;
bool delayed_gc_task_pending_ = false;
bool eager_gc_task_pending_ = false;
base::RandomNumberGenerator random_number_generator_;
};
// Infers the native context for some of the heap objects.
......
......@@ -130,6 +130,88 @@ TEST(NativeContextStatsExternalString) {
CHECK_EQ(10 + 10 * 2, stats.Get(native_context->ptr()));
}
namespace {
class MockPlatform : public TestPlatform {
public:
MockPlatform()
: old_platform_(i::V8::GetCurrentPlatform()),
mock_task_runner_(new MockTaskRunner()) {
// Now that it's completely constructed, make this the current platform.
i::V8::SetPlatformForTesting(this);
}
~MockPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
v8::Isolate*) override {
return mock_task_runner_;
}
double Delay() { return mock_task_runner_->Delay(); }
void PerformTask() { mock_task_runner_->PerformTask(); }
private:
class MockTaskRunner : public v8::TaskRunner {
public:
void PostTask(std::unique_ptr<v8::Task> task) override {}
void PostDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) override {
task_ = std::move(task);
delay_ = delay_in_seconds;
}
void PostIdleTask(std::unique_ptr<IdleTask> task) override {
UNREACHABLE();
}
bool IdleTasksEnabled() override { return false; }
double Delay() { return delay_; }
void PerformTask() {
std::unique_ptr<Task> task = std::move(task_);
task->Run();
}
private:
double delay_ = -1;
std::unique_ptr<Task> task_;
};
v8::Platform* old_platform_;
std::shared_ptr<MockTaskRunner> mock_task_runner_;
};
class MockMeasureMemoryDelegate : public v8::MeasureMemoryDelegate {
public:
bool ShouldMeasure(v8::Local<v8::Context> context) override { return true; }
void MeasurementComplete(
const std::vector<std::pair<v8::Local<v8::Context>, size_t>>&
context_sizes_in_bytes,
size_t unattributed_size_in_bytes) override {
// Empty.
}
};
} // namespace
TEST(RandomizedTimeout) {
CcTest::InitializeVM();
MockPlatform platform;
std::vector<double> delays;
for (int i = 0; i < 10; i++) {
CcTest::isolate()->MeasureMemory(
std::make_unique<MockMeasureMemoryDelegate>());
delays.push_back(platform.Delay());
platform.PerformTask();
}
std::sort(delays.begin(), delays.end());
CHECK_LT(delays[0], delays.back());
}
} // namespace heap
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment