Skip to content

Commit

Permalink
Add an experiment for enabling V8's memory savings mode on Android.
Browse files Browse the repository at this point in the history
This feature works in conjunction with --site-per-process. When a renderer
process has only subframes, Blink's main thread isolate will be put
into a memory savings mode. If a main frame is created in the process,
the isolate will be taken out of memory savings mode for as long as a main
frame exists.

Bug: 846360
Change-Id: I09c362cce648b734fb01907a5ad758f0bdb7f752
Reviewed-on: https://chromium-review.googlesource.com/1076954
Reviewed-by: Brian White <bcwhite@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#564881}
  • Loading branch information
rsesek authored and Commit Bot committed Jun 6, 2018
1 parent 33eb088 commit 6e3d725
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 0 deletions.
5 changes: 5 additions & 0 deletions content/browser/renderer_host/render_process_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1662,6 +1662,11 @@ bool RenderProcessHostImpl::Init() {

GetRendererInterface()->SetUserAgent(GetContentClient()->GetUserAgent());

if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites() &&
base::FeatureList::IsEnabled(features::kV8LowMemoryModeForSubframes)) {
GetRendererInterface()->EnableV8LowMemoryMode();
}

is_initialized_ = true;
init_time_ = base::TimeTicks::Now();
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ class EmbeddedWorkerTestHelper::MockRendererInterface : public mojom::Renderer {
void SetSchedulerKeepActive(bool keep_active) override { NOTREACHED(); }
void ProcessPurgeAndSuspend() override { NOTREACHED(); }
void SetIsLockedToSite() override { NOTREACHED(); }
void EnableV8LowMemoryMode() override { NOTREACHED(); }

base::WeakPtr<EmbeddedWorkerTestHelper> helper_;
mojo::AssociatedBindingSet<mojom::Renderer> bindings_;
Expand Down
7 changes: 7 additions & 0 deletions content/common/renderer.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,11 @@ interface Renderer {
// scheme plus eTLD+1, such as https://google.com), or to a more specific
// origin.
SetIsLockedToSite();

// Tells the renderer to enable V8's memory saving mode when possible.
// This is only used when site-per-process is enabled. If the process
// only contains subframes, V8's low memory mode will be enabled.
// If a main frame exists or is created, the low memory mode will
// be disabled.
EnableV8LowMemoryMode();
};
5 changes: 5 additions & 0 deletions content/public/common/content_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ const base::Feature kUseVideoCaptureApiForDevToolsSnapshots{
const base::Feature kV8ContextSnapshot{"V8ContextSnapshot",
base::FEATURE_ENABLED_BY_DEFAULT};

// Enables V8's low memory mode for subframes. This is used only
// in conjunction with the --site-per-process feature.
const base::Feature kV8LowMemoryModeForSubframes{
"V8LowMemoryModeForSubframes", base::FEATURE_DISABLED_BY_DEFAULT};

// Enables to use the V8 Orinoco garbage collector.
const base::Feature kV8Orinoco{"V8Orinoco", base::FEATURE_ENABLED_BY_DEFAULT};

Expand Down
1 change: 1 addition & 0 deletions content/public/common/content_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ CONTENT_EXPORT extern const base::Feature kUserActivationV2;
CONTENT_EXPORT extern const base::Feature
kUseVideoCaptureApiForDevToolsSnapshots;
CONTENT_EXPORT extern const base::Feature kV8ContextSnapshot;
CONTENT_EXPORT extern const base::Feature kV8LowMemoryModeForSubframes;
CONTENT_EXPORT extern const base::Feature kV8Orinoco;
CONTENT_EXPORT extern const base::Feature kV8VmFuture;
CONTENT_EXPORT extern const base::Feature kVrWebInputEditing;
Expand Down
2 changes: 2 additions & 0 deletions content/renderer/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ target(link_target_type, "renderer") {
"loader/web_url_request_util.h",
"loader/weburlresponse_extradata_impl.cc",
"loader/weburlresponse_extradata_impl.h",
"low_memory_mode_controller.cc",
"low_memory_mode_controller.h",
"manifest/manifest_change_notifier.cc",
"manifest/manifest_change_notifier.h",
"manifest/manifest_manager.cc",
Expand Down
61 changes: 61 additions & 0 deletions content/renderer/low_memory_mode_controller.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/low_memory_mode_controller.h"

#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/web/blink.h"
#include "v8/include/v8.h"

namespace content {

LowMemoryModeController::LowMemoryModeController() = default;

LowMemoryModeController::~LowMemoryModeController() = default;

void LowMemoryModeController::OnFrameCreated(bool is_main_frame) {
if (is_main_frame) {
// If the process is gaining its first main frame, disable memory
// savings mode.
if (++main_frame_count_ == 1) {
Disable();
}
} else if (main_frame_count_ == 0) {
// The process is getting a new frame and none is main, enable
// memory savings mode (if not already on).
Enable();
}
}

void LowMemoryModeController::OnFrameDestroyed(bool is_main_frame) {
// If the process is losing its last main frame, enable memory
// savings mode.
if (is_main_frame && --main_frame_count_ == 0) {
Enable();
}
}

void LowMemoryModeController::Enable() {
if (is_enabled_)
return;

blink::MainThreadIsolate()->EnableMemorySavingsMode();
RecordHistogram(true);
is_enabled_ = true;
}

void LowMemoryModeController::Disable() {
if (!is_enabled_)
return;

blink::MainThreadIsolate()->DisableMemorySavingsMode();
RecordHistogram(false);
is_enabled_ = false;
}

void LowMemoryModeController::RecordHistogram(bool enabled) {
UMA_HISTOGRAM_BOOLEAN("SiteIsolation.LowMemoryMode.Transition", enabled);
}

} // namespace content
58 changes: 58 additions & 0 deletions content/renderer/low_memory_mode_controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_RENDERER_LOW_MEMORY_MODE_CONTROLLER_H_
#define CONTENT_RENDERER_LOW_MEMORY_MODE_CONTROLLER_H_

#include <memory>

#include "base/macros.h"
#include "content/common/content_export.h"

namespace content {

// The LowMemoryModeController manages for a renderer process the blink
// main thread isolate's memory savings mode state. This is only enabled
// if the V8LowMemoryModeForNonMainFrames feature and --site-per-process
// are enabled.
//
// When a process only contains subframes, the memory saving mode is
// enabled. If a main frame is later created, then the mode is disabled
// for the duration of the main frame's existence.
//
// The default state after initialization is to not enable low memory mode.
class CONTENT_EXPORT LowMemoryModeController {
public:
LowMemoryModeController();
~LowMemoryModeController();

// Notifies the controller that a frame has either been created or
// destroyed. A transition to the memory saving mode may occur as a result.
void OnFrameCreated(bool is_main_frame);
void OnFrameDestroyed(bool is_main_frame);

bool is_enabled() const { return is_enabled_; }

private:
// Puts the main thread isolate into memory savings mode if it is not
// currently enabled.
void Enable();

// Takes the main thread isolate out of memory savings mode if it is
// currently enabled.
void Disable();

// Records an UMA histogram marking an Enabled->Disabled state transition,
// or vice versa.
void RecordHistogram(bool enabled);

int main_frame_count_ = 0;
bool is_enabled_ = false;

DISALLOW_COPY_AND_ASSIGN(LowMemoryModeController);
};

} // namespace content

#endif // CONTENT_RENDERER_LOW_MEMORY_MODE_CONTROLLER_H_
86 changes: 86 additions & 0 deletions content/renderer/low_memory_mode_controller_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/low_memory_mode_controller.h"

#include "base/test/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace content {
namespace {

class LowMemoryModeControllerTest : public testing::Test {
public:
LowMemoryModeController* controller() { return &controller_; }

void ExpectTransitionCount(int enabled_count, int disabled_count) {
static constexpr char kHistogram[] =
"SiteIsolation.LowMemoryMode.Transition";
histogram_tester_.ExpectBucketCount(kHistogram, true, enabled_count);
histogram_tester_.ExpectBucketCount(kHistogram, false, disabled_count);
histogram_tester_.ExpectTotalCount(kHistogram,
enabled_count + disabled_count);
}

private:
base::HistogramTester histogram_tester_;
LowMemoryModeController controller_;
};

TEST_F(LowMemoryModeControllerTest, CreateMainFrames) {
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameCreated(true);
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameCreated(true);
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameDestroyed(true);
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameDestroyed(true);
EXPECT_TRUE(controller()->is_enabled());

ExpectTransitionCount(1, 0);
}

TEST_F(LowMemoryModeControllerTest, MainFrameAddSubframe) {
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameCreated(true);
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameCreated(false);
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameDestroyed(true);
EXPECT_TRUE(controller()->is_enabled());

controller()->OnFrameDestroyed(false);
EXPECT_TRUE(controller()->is_enabled());

ExpectTransitionCount(1, 0);
}

TEST_F(LowMemoryModeControllerTest, SubFrameAddMainFrame) {
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameCreated(false);
EXPECT_TRUE(controller()->is_enabled());

controller()->OnFrameCreated(true);
EXPECT_FALSE(controller()->is_enabled());

controller()->OnFrameDestroyed(true);
EXPECT_TRUE(controller()->is_enabled());

controller()->OnFrameDestroyed(false);
EXPECT_TRUE(controller()->is_enabled());

ExpectTransitionCount(2, 1);
}

} // namespace
} // namespace content
13 changes: 13 additions & 0 deletions content/renderer/render_frame_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
#include "content/renderer/loader/web_url_loader_impl.h"
#include "content/renderer/loader/web_url_request_util.h"
#include "content/renderer/loader/weburlresponse_extradata_impl.h"
#include "content/renderer/low_memory_mode_controller.h"
#include "content/renderer/manifest/manifest_change_notifier.h"
#include "content/renderer/manifest/manifest_manager.h"
#include "content/renderer/media/audio_device_factory.h"
Expand Down Expand Up @@ -1407,6 +1408,12 @@ RenderFrameImpl::~RenderFrameImpl() {
if (auto* factory = AudioOutputIPCFactory::get())
factory->MaybeDeregisterRemoteFactory(GetRoutingID());

// |thread| may be null in tests.
if (auto* thread = RenderThreadImpl::current()) {
if (auto* controller = thread->low_memory_mode_controller())
controller->OnFrameDestroyed(IsMainFrame());
}

if (is_main_frame_) {
// Ensure the RenderView doesn't point to this object, once it is destroyed.
// TODO(nasko): Add a check that the |main_render_frame_| of |render_view_|
Expand Down Expand Up @@ -1442,6 +1449,12 @@ void RenderFrameImpl::Initialize() {
"parent", parent_id);
}

// |thread| may be null in tests.
if (auto* thread = RenderThreadImpl::current()) {
if (auto* controller = thread->low_memory_mode_controller())
controller->OnFrameCreated(IsMainFrame());
}

#if BUILDFLAG(ENABLE_PLUGINS)
new PepperBrowserConnection(this);
#endif
Expand Down
6 changes: 6 additions & 0 deletions content/renderer/render_thread_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#include "content/renderer/indexed_db/indexed_db_dispatcher.h"
#include "content/renderer/input/widget_input_handler_manager.h"
#include "content/renderer/loader/resource_dispatcher.h"
#include "content/renderer/low_memory_mode_controller.h"
#include "content/renderer/media/audio_renderer_mixer_manager.h"
#include "content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h"
#include "content/renderer/media/midi/midi_message_filter.h"
Expand Down Expand Up @@ -1787,6 +1788,11 @@ void RenderThreadImpl::SetIsLockedToSite() {
blink_platform_impl_->SetIsLockedToSite();
}

void RenderThreadImpl::EnableV8LowMemoryMode() {
if (!low_memory_mode_controller_)
low_memory_mode_controller_.reset(new LowMemoryModeController());
}

bool RenderThreadImpl::GetRendererMemoryMetrics(
RendererMemoryMetrics* memory_metrics) const {
DCHECK(memory_metrics);
Expand Down
10 changes: 10 additions & 0 deletions content/renderer/render_thread_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class FileSystemDispatcher;
class FrameSwapMessageQueue;
class GpuVideoAcceleratorFactoriesImpl;
class IndexedDBDispatcher;
class LowMemoryModeController;
class MidiMessageFilter;
class P2PSocketDispatcher;
class PeerConnectionDependencyFactory;
Expand Down Expand Up @@ -372,6 +373,10 @@ class CONTENT_EXPORT RenderThreadImpl
return vc_manager_.get();
}

LowMemoryModeController* low_memory_mode_controller() const {
return low_memory_mode_controller_.get();
}

mojom::RenderFrameMessageFilter* render_frame_message_filter();
mojom::RenderMessageFilter* render_message_filter();

Expand Down Expand Up @@ -579,6 +584,7 @@ class CONTENT_EXPORT RenderThreadImpl
void SetSchedulerKeepActive(bool keep_active) override;
void ProcessPurgeAndSuspend() override;
void SetIsLockedToSite() override;
void EnableV8LowMemoryMode() override;

void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
Expand Down Expand Up @@ -720,6 +726,10 @@ class CONTENT_EXPORT RenderThreadImpl

std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;

// Created in response to EnableV8LowMemoryMode(), this manages V8's
// memory saving mode.
std::unique_ptr<LowMemoryModeController> low_memory_mode_controller_;

std::unique_ptr<ui::Gpu> gpu_;

scoped_refptr<base::SingleThreadTaskRunner>
Expand Down
1 change: 1 addition & 0 deletions content/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,7 @@ test("content_unittests") {
"../renderer/loader/url_response_body_consumer_unittest.cc",
"../renderer/loader/web_data_consumer_handle_impl_unittest.cc",
"../renderer/loader/web_url_loader_impl_unittest.cc",
"../renderer/low_memory_mode_controller_unittest.cc",
"../renderer/manifest/manifest_parser_unittest.cc",
"../renderer/media/audio_output_ipc_factory_unittest.cc",
"../renderer/media/audio_renderer_mixer_manager_unittest.cc",
Expand Down
21 changes: 21 additions & 0 deletions testing/variations/fieldtrial_testing_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4262,6 +4262,27 @@
]
}
],
"V8LowMemoryModeForSubframes": [
{
"platforms": [
"android"
],
"experiments": [
{
"name": "Enabled",
"enable_features": [
"V8LowMemoryModeForSubframes"
]
},
{
"name": "Disabled",
"disable_features": [
"V8LowMemoryModeForSubframes"
]
}
]
}
],
"V8WasmTrapHandler": [
{
"platforms": [
Expand Down
Loading

0 comments on commit 6e3d725

Please sign in to comment.