Commit cd540b30 authored by Joe Mason's avatar Joe Mason Committed by Commit Bot

[PM] Add a lazy mode to V8PerFrameMemoryRequest

R=chrisha

Bug: 1080672
Change-Id: I4b24d1e77e9dcc228d606f6d484127b04ca0dadc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2339219
Commit-Queue: Joe Mason <joenotcharles@chromium.org>
Reviewed-by: default avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: default avatarChris Hamilton <chrisha@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798718}
parent 6695ffa6
...@@ -264,9 +264,8 @@ class V8PerFrameMemoryDecorator ...@@ -264,9 +264,8 @@ class V8PerFrameMemoryDecorator
base::Value DescribeFrameNodeData(const FrameNode* node) const override; base::Value DescribeFrameNodeData(const FrameNode* node) const override;
base::Value DescribeProcessNodeData(const ProcessNode* node) const override; base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
// Returns the amount of time to wait between requests for each process. // Returns the next measurement request that should be scheduled.
// Returns a zero TimeDelta if no requests should be made. V8PerFrameMemoryRequest* GetNextRequest() const;
base::TimeDelta GetMinTimeBetweenRequestsPerProcess() const;
// Implementation details below this point. // Implementation details below this point.
...@@ -288,7 +287,7 @@ class V8PerFrameMemoryDecorator ...@@ -288,7 +287,7 @@ class V8PerFrameMemoryDecorator
Graph* graph_ = nullptr; Graph* graph_ = nullptr;
// List of requests sorted by sample_frequency (lowest first). // List of requests sorted by min_time_between_requests (lowest first).
std::vector<V8PerFrameMemoryRequest*> measurement_requests_; std::vector<V8PerFrameMemoryRequest*> measurement_requests_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
...@@ -296,25 +295,54 @@ class V8PerFrameMemoryDecorator ...@@ -296,25 +295,54 @@ class V8PerFrameMemoryDecorator
class V8PerFrameMemoryRequest { class V8PerFrameMemoryRequest {
public: public:
enum class MeasurementMode {
// Measurements will be taken at the next GC after a request is received.
// If no GC happens within a bounded time an extra GC will be scheduled.
kBounded,
// Measurements will only be taken at the next scheduled GC after a request
// is received.
kLazy,
kDefault = kBounded,
};
// Creates a request but does not start the measurements. Call // Creates a request but does not start the measurements. Call
// StartMeasurement to add it to the request list. // StartMeasurement to add it to the request list.
explicit V8PerFrameMemoryRequest(const base::TimeDelta& sample_frequency); //
// Measurement requests will be sent repeatedly to each process, with at
// least |min_time_between_requests| (which must be greater than 0) between
// each repetition. The next GC after each request is received will be
// instrumented, which adds some overhead. |mode| determines whether extra
// GC's can be scheduled, which would add even more overhead.
explicit V8PerFrameMemoryRequest(
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode = MeasurementMode::kDefault);
// Creates a request and calls StartMeasurement with the given |graph| and
// |min_time_between_requests|, using the default measurement mode.
V8PerFrameMemoryRequest(const base::TimeDelta& min_time_between_requests,
Graph* graph);
// Creates a request and calls StartMeasurement. This will request // Creates a request and calls StartMeasurement with the given |graph|,
// measurements for all ProcessNode's in |graph| with frequency // |min_time_between_requests|, and |mode|.
// |sample_frequency|. V8PerFrameMemoryRequest(const base::TimeDelta& min_time_between_requests,
V8PerFrameMemoryRequest(const base::TimeDelta& sample_frequency, MeasurementMode mode,
Graph* graph); Graph* graph);
~V8PerFrameMemoryRequest(); ~V8PerFrameMemoryRequest();
V8PerFrameMemoryRequest(const V8PerFrameMemoryRequest&) = delete; V8PerFrameMemoryRequest(const V8PerFrameMemoryRequest&) = delete;
V8PerFrameMemoryRequest& operator=(const V8PerFrameMemoryRequest&) = delete; V8PerFrameMemoryRequest& operator=(const V8PerFrameMemoryRequest&) = delete;
const base::TimeDelta& sample_frequency() const { return sample_frequency_; } const base::TimeDelta& min_time_between_requests() const {
return min_time_between_requests_;
}
MeasurementMode mode() const { return mode_; }
// Requests measurements for all ProcessNode's in |graph| with this object's // Requests measurements for all ProcessNode's in |graph|. This must only be
// sample frequency. This must only be called once for each // called once for each V8PerFrameMemoryRequest.
// V8PerFrameMemoryRequest.
void StartMeasurement(Graph* graph); void StartMeasurement(Graph* graph);
// Adds/removes an observer. // Adds/removes an observer.
...@@ -326,10 +354,11 @@ class V8PerFrameMemoryRequest { ...@@ -326,10 +354,11 @@ class V8PerFrameMemoryRequest {
// Private constructor for V8PerFrameMemoryRequestAnySeq. Saves // Private constructor for V8PerFrameMemoryRequestAnySeq. Saves
// |off_sequence_request| as a pointer to the off-sequence object that // |off_sequence_request| as a pointer to the off-sequence object that
// triggered the request and starts measurements with frequency // triggered the request and starts measurements with frequency
// |sample_frequency|. // |min_time_between_requests|.
V8PerFrameMemoryRequest( V8PerFrameMemoryRequest(
util::PassKey<V8PerFrameMemoryRequestAnySeq>, util::PassKey<V8PerFrameMemoryRequestAnySeq>,
const base::TimeDelta& sample_frequency, const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request); base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request);
// V8PerFrameMemoryDecorator calls OnDecoratorUnregistered when it is removed // V8PerFrameMemoryDecorator calls OnDecoratorUnregistered when it is removed
...@@ -343,7 +372,8 @@ class V8PerFrameMemoryRequest { ...@@ -343,7 +372,8 @@ class V8PerFrameMemoryRequest {
const ProcessNode* process_node) const; const ProcessNode* process_node) const;
private: private:
base::TimeDelta sample_frequency_; base::TimeDelta min_time_between_requests_;
MeasurementMode mode_;
V8PerFrameMemoryDecorator* decorator_ = nullptr; V8PerFrameMemoryDecorator* decorator_ = nullptr;
base::ObserverList<V8PerFrameMemoryObserver, /*check_empty=*/true> observers_; base::ObserverList<V8PerFrameMemoryObserver, /*check_empty=*/true> observers_;
...@@ -450,8 +480,11 @@ class V8PerFrameMemoryObserverAnySeq : public base::CheckedObserver { ...@@ -450,8 +480,11 @@ class V8PerFrameMemoryObserverAnySeq : public base::CheckedObserver {
// Wrapper that can instantiate a V8PerFrameMemoryRequest from any sequence. // Wrapper that can instantiate a V8PerFrameMemoryRequest from any sequence.
class V8PerFrameMemoryRequestAnySeq { class V8PerFrameMemoryRequestAnySeq {
public: public:
using MeasurementMode = V8PerFrameMemoryRequest::MeasurementMode;
explicit V8PerFrameMemoryRequestAnySeq( explicit V8PerFrameMemoryRequestAnySeq(
const base::TimeDelta& sample_frequency); const base::TimeDelta& min_time_between_requests,
MeasurementMode mode = MeasurementMode::kDefault);
~V8PerFrameMemoryRequestAnySeq(); ~V8PerFrameMemoryRequestAnySeq();
V8PerFrameMemoryRequestAnySeq(const V8PerFrameMemoryRequestAnySeq&) = delete; V8PerFrameMemoryRequestAnySeq(const V8PerFrameMemoryRequestAnySeq&) = delete;
......
...@@ -48,6 +48,8 @@ class V8PerFrameMemoryDecorator::ObserverNotifier { ...@@ -48,6 +48,8 @@ class V8PerFrameMemoryDecorator::ObserverNotifier {
namespace { namespace {
using MeasurementMode = V8PerFrameMemoryRequest::MeasurementMode;
using PerFrameUsagePtr = blink::mojom::PerFrameV8MemoryUsageDataPtr; using PerFrameUsagePtr = blink::mojom::PerFrameV8MemoryUsageDataPtr;
// Comparator that generates a strict total order of PerFrameUsagePtr's when // Comparator that generates a strict total order of PerFrameUsagePtr's when
...@@ -185,7 +187,7 @@ class NodeAttachedProcessData ...@@ -185,7 +187,7 @@ class NodeAttachedProcessData
void ScheduleNextMeasurement(); void ScheduleNextMeasurement();
private: private:
void StartMeasurement(); void StartMeasurement(MeasurementMode mode);
void EnsureRemote(); void EnsureRemote();
void OnPerFrameV8MemoryUsageData( void OnPerFrameV8MemoryUsageData(
blink::mojom::PerProcessV8MemoryUsageDataPtr result); blink::mojom::PerProcessV8MemoryUsageDataPtr result);
...@@ -228,10 +230,14 @@ void NodeAttachedProcessData::ScheduleNextMeasurement() { ...@@ -228,10 +230,14 @@ void NodeAttachedProcessData::ScheduleNextMeasurement() {
return; return;
} }
V8PerFrameMemoryRequest* next_request = nullptr;
auto* decorator = auto* decorator =
V8PerFrameMemoryDecorator::GetFromGraph(process_node_->GetGraph()); V8PerFrameMemoryDecorator::GetFromGraph(process_node_->GetGraph());
if (!decorator || if (decorator) {
decorator->GetMinTimeBetweenRequestsPerProcess().is_zero()) { next_request = decorator->GetNextRequest();
}
if (!next_request) {
// All measurements have been cancelled, or decorator was removed from // All measurements have been cancelled, or decorator was removed from
// graph. // graph.
state_ = State::kIdle; state_ = State::kIdle;
...@@ -243,17 +249,20 @@ void NodeAttachedProcessData::ScheduleNextMeasurement() { ...@@ -243,17 +249,20 @@ void NodeAttachedProcessData::ScheduleNextMeasurement() {
state_ = State::kWaiting; state_ = State::kWaiting;
if (last_request_time_.is_null()) { if (last_request_time_.is_null()) {
// This is the first measurement. Perform it immediately. // This is the first measurement. Perform it immediately.
StartMeasurement(); StartMeasurement(next_request->mode());
return; return;
} }
// TODO(joenotcharles): Make sure kLazy requests can't starve kBounded
// requests.
base::TimeTicks next_request_time = base::TimeTicks next_request_time =
last_request_time_ + decorator->GetMinTimeBetweenRequestsPerProcess(); last_request_time_ + next_request->min_time_between_requests();
timer_.Start(FROM_HERE, next_request_time - base::TimeTicks::Now(), this, timer_.Start(FROM_HERE, next_request_time - base::TimeTicks::Now(),
&NodeAttachedProcessData::StartMeasurement); base::BindOnce(&NodeAttachedProcessData::StartMeasurement,
base::Unretained(this), next_request->mode()));
} }
void NodeAttachedProcessData::StartMeasurement() { void NodeAttachedProcessData::StartMeasurement(MeasurementMode mode) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(state_, State::kWaiting); DCHECK_EQ(state_, State::kWaiting);
state_ = State::kMeasuring; state_ = State::kMeasuring;
...@@ -268,7 +277,9 @@ void NodeAttachedProcessData::StartMeasurement() { ...@@ -268,7 +277,9 @@ void NodeAttachedProcessData::StartMeasurement() {
// NodeAttachedProcessData when the last V8PerFrameMemoryRequest is deleted, // NodeAttachedProcessData when the last V8PerFrameMemoryRequest is deleted,
// which could happen at any time. // which could happen at any time.
resource_usage_reporter_->GetPerFrameV8MemoryUsageData( resource_usage_reporter_->GetPerFrameV8MemoryUsageData(
blink::mojom::V8PerFrameMemoryReporter::Mode::DEFAULT, mode == MeasurementMode::kLazy
? blink::mojom::V8PerFrameMemoryReporter::Mode::LAZY
: blink::mojom::V8PerFrameMemoryReporter::Mode::DEFAULT,
base::BindOnce(&NodeAttachedProcessData::OnPerFrameV8MemoryUsageData, base::BindOnce(&NodeAttachedProcessData::OnPerFrameV8MemoryUsageData,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
...@@ -371,16 +382,25 @@ void SetBindV8PerFrameMemoryReporterCallbackForTesting( ...@@ -371,16 +382,25 @@ void SetBindV8PerFrameMemoryReporterCallbackForTesting(
// V8PerFrameMemoryRequest // V8PerFrameMemoryRequest
V8PerFrameMemoryRequest::V8PerFrameMemoryRequest( V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
const base::TimeDelta& sample_frequency) const base::TimeDelta& min_time_between_requests,
: sample_frequency_(sample_frequency) { MeasurementMode mode)
DCHECK_GT(sample_frequency_, base::TimeDelta()); : min_time_between_requests_(min_time_between_requests), mode_(mode) {
DCHECK_GT(min_time_between_requests_, base::TimeDelta());
} }
V8PerFrameMemoryRequest::V8PerFrameMemoryRequest( V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
const base::TimeDelta& sample_frequency, const base::TimeDelta& min_time_between_requests,
Graph* graph) Graph* graph)
: sample_frequency_(sample_frequency) { : V8PerFrameMemoryRequest(min_time_between_requests,
DCHECK_GT(sample_frequency_, base::TimeDelta()); MeasurementMode::kDefault) {
StartMeasurement(graph);
}
V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
Graph* graph)
: V8PerFrameMemoryRequest(min_time_between_requests, mode) {
StartMeasurement(graph); StartMeasurement(graph);
} }
...@@ -388,12 +408,13 @@ V8PerFrameMemoryRequest::V8PerFrameMemoryRequest( ...@@ -388,12 +408,13 @@ V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
// sequence. // sequence.
V8PerFrameMemoryRequest::V8PerFrameMemoryRequest( V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
util::PassKey<V8PerFrameMemoryRequestAnySeq>, util::PassKey<V8PerFrameMemoryRequestAnySeq>,
const base::TimeDelta& sample_frequency, const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request) base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request)
: sample_frequency_(sample_frequency), : V8PerFrameMemoryRequest(min_time_between_requests, mode) {
off_sequence_request_(std::move(off_sequence_request)),
off_sequence_request_sequence_(base::SequencedTaskRunnerHandle::Get()) {
DETACH_FROM_SEQUENCE(sequence_checker_); DETACH_FROM_SEQUENCE(sequence_checker_);
off_sequence_request_ = std::move(off_sequence_request);
off_sequence_request_sequence_ = base::SequencedTaskRunnerHandle::Get();
// Unretained is safe since |this| will be destroyed on the graph sequence. // Unretained is safe since |this| will be destroyed on the graph sequence.
PerformanceManager::CallOnGraph( PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce(&V8PerFrameMemoryRequest::StartMeasurement, FROM_HERE, base::BindOnce(&V8PerFrameMemoryRequest::StartMeasurement,
...@@ -586,12 +607,10 @@ base::Value V8PerFrameMemoryDecorator::DescribeProcessNodeData( ...@@ -586,12 +607,10 @@ base::Value V8PerFrameMemoryDecorator::DescribeProcessNodeData(
return dict; return dict;
} }
base::TimeDelta V8PerFrameMemoryDecorator::GetMinTimeBetweenRequestsPerProcess() V8PerFrameMemoryRequest* V8PerFrameMemoryDecorator::GetNextRequest() const {
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return measurement_requests_.empty() return measurement_requests_.empty() ? nullptr
? base::TimeDelta() : measurement_requests_.front();
: measurement_requests_.front()->sample_frequency();
} }
void V8PerFrameMemoryDecorator::AddMeasurementRequest( void V8PerFrameMemoryDecorator::AddMeasurementRequest(
...@@ -607,7 +626,14 @@ void V8PerFrameMemoryDecorator::AddMeasurementRequest( ...@@ -607,7 +626,14 @@ void V8PerFrameMemoryDecorator::AddMeasurementRequest(
for (std::vector<V8PerFrameMemoryRequest*>::const_iterator it = for (std::vector<V8PerFrameMemoryRequest*>::const_iterator it =
measurement_requests_.begin(); measurement_requests_.begin();
it != measurement_requests_.end(); ++it) { it != measurement_requests_.end(); ++it) {
if (request->sample_frequency() < (*it)->sample_frequency()) { if (request->min_time_between_requests() <
(*it)->min_time_between_requests() ||
// Make sure bounded request sort before lazy requests so that they
// aren't starved.
(request->min_time_between_requests() ==
(*it)->min_time_between_requests() &&
request->mode() ==
V8PerFrameMemoryRequest::MeasurementMode::kBounded)) {
measurement_requests_.insert(it, request); measurement_requests_.insert(it, request);
UpdateProcessMeasurementSchedules(); UpdateProcessMeasurementSchedules();
return; return;
...@@ -636,8 +662,8 @@ void V8PerFrameMemoryDecorator::UpdateProcessMeasurementSchedules() const { ...@@ -636,8 +662,8 @@ void V8PerFrameMemoryDecorator::UpdateProcessMeasurementSchedules() const {
for (size_t i = 1; i < measurement_requests_.size(); ++i) { for (size_t i = 1; i < measurement_requests_.size(); ++i) {
DCHECK(measurement_requests_[i - 1]); DCHECK(measurement_requests_[i - 1]);
DCHECK(measurement_requests_[i]); DCHECK(measurement_requests_[i]);
DCHECK_LE(measurement_requests_[i - 1]->sample_frequency(), DCHECK_LE(measurement_requests_[i - 1]->min_time_between_requests(),
measurement_requests_[i]->sample_frequency()); measurement_requests_[i]->min_time_between_requests());
} }
#endif #endif
for (const ProcessNode* node : graph_->GetAllProcessNodes()) { for (const ProcessNode* node : graph_->GetAllProcessNodes()) {
...@@ -666,7 +692,8 @@ void V8PerFrameMemoryDecorator::NotifyObserversOnMeasurementAvailable( ...@@ -666,7 +692,8 @@ void V8PerFrameMemoryDecorator::NotifyObserversOnMeasurementAvailable(
// V8PerFrameMemoryRequestAnySeq // V8PerFrameMemoryRequestAnySeq
V8PerFrameMemoryRequestAnySeq::V8PerFrameMemoryRequestAnySeq( V8PerFrameMemoryRequestAnySeq::V8PerFrameMemoryRequestAnySeq(
const base::TimeDelta& sample_frequency) { const base::TimeDelta& min_time_between_requests,
MeasurementMode mode) {
// |request_| must be initialized in the constructor body so that // |request_| must be initialized in the constructor body so that
// |weak_factory_| is completely constructed. // |weak_factory_| is completely constructed.
// //
...@@ -674,8 +701,8 @@ V8PerFrameMemoryRequestAnySeq::V8PerFrameMemoryRequestAnySeq( ...@@ -674,8 +701,8 @@ V8PerFrameMemoryRequestAnySeq::V8PerFrameMemoryRequestAnySeq(
// constructor. After construction the V8PerFrameMemoryRequest must only be // constructor. After construction the V8PerFrameMemoryRequest must only be
// accessed on the graph sequence. // accessed on the graph sequence.
request_ = base::WrapUnique(new V8PerFrameMemoryRequest( request_ = base::WrapUnique(new V8PerFrameMemoryRequest(
util::PassKey<V8PerFrameMemoryRequestAnySeq>(), sample_frequency, util::PassKey<V8PerFrameMemoryRequestAnySeq>(), min_time_between_requests,
weak_factory_.GetWeakPtr())); mode, weak_factory_.GetWeakPtr()));
} }
V8PerFrameMemoryRequestAnySeq::~V8PerFrameMemoryRequestAnySeq() { V8PerFrameMemoryRequestAnySeq::~V8PerFrameMemoryRequestAnySeq() {
......
...@@ -142,8 +142,10 @@ class V8PerFrameMemoryDecoratorTestBase { ...@@ -142,8 +142,10 @@ class V8PerFrameMemoryDecoratorTestBase {
MockV8PerFrameMemoryReporter* mock_reporter, MockV8PerFrameMemoryReporter* mock_reporter,
base::RepeatingCallback<void( base::RepeatingCallback<void(
MockV8PerFrameMemoryReporter::GetPerFrameV8MemoryUsageDataCallback MockV8PerFrameMemoryReporter::GetPerFrameV8MemoryUsageDataCallback
callback)> responder) { callback)> responder,
EXPECT_CALL(*mock_reporter, GetPerFrameV8MemoryUsageData(_, _)) MockV8PerFrameMemoryReporter::Mode expected_mode =
MockV8PerFrameMemoryReporter::Mode::DEFAULT) {
EXPECT_CALL(*mock_reporter, GetPerFrameV8MemoryUsageData(expected_mode, _))
.WillOnce([this, responder]( .WillOnce([this, responder](
MockV8PerFrameMemoryReporter::Mode mode, MockV8PerFrameMemoryReporter::Mode mode,
MockV8PerFrameMemoryReporter:: MockV8PerFrameMemoryReporter::
...@@ -154,29 +156,37 @@ class V8PerFrameMemoryDecoratorTestBase { ...@@ -154,29 +156,37 @@ class V8PerFrameMemoryDecoratorTestBase {
} }
void ExpectQueryAndReply(MockV8PerFrameMemoryReporter* mock_reporter, void ExpectQueryAndReply(MockV8PerFrameMemoryReporter* mock_reporter,
blink::mojom::PerProcessV8MemoryUsageDataPtr data) { blink::mojom::PerProcessV8MemoryUsageDataPtr data,
MockV8PerFrameMemoryReporter::Mode expected_mode =
MockV8PerFrameMemoryReporter::Mode::DEFAULT) {
ExpectQuery( ExpectQuery(
mock_reporter, mock_reporter,
base::BindRepeating(&V8PerFrameMemoryDecoratorTestBase::ReplyWithData, base::BindRepeating(&V8PerFrameMemoryDecoratorTestBase::ReplyWithData,
base::Unretained(this), base::Passed(&data))); base::Unretained(this), base::Passed(&data)),
expected_mode);
} }
void ExpectQueryAndDelayReply( void ExpectQueryAndDelayReply(
MockV8PerFrameMemoryReporter* mock_reporter, MockV8PerFrameMemoryReporter* mock_reporter,
const base::TimeDelta& delay, const base::TimeDelta& delay,
blink::mojom::PerProcessV8MemoryUsageDataPtr data) { blink::mojom::PerProcessV8MemoryUsageDataPtr data,
MockV8PerFrameMemoryReporter::Mode expected_mode =
MockV8PerFrameMemoryReporter::Mode::DEFAULT) {
ExpectQuery(mock_reporter, ExpectQuery(mock_reporter,
base::BindRepeating( base::BindRepeating(
&V8PerFrameMemoryDecoratorTestBase::DelayedReplyWithData, &V8PerFrameMemoryDecoratorTestBase::DelayedReplyWithData,
base::Unretained(this), delay, base::Passed(&data))); base::Unretained(this), delay, base::Passed(&data)),
expected_mode);
} }
void ExpectBindAndRespondToQuery( void ExpectBindAndRespondToQuery(
MockV8PerFrameMemoryReporter* mock_reporter, MockV8PerFrameMemoryReporter* mock_reporter,
blink::mojom::PerProcessV8MemoryUsageDataPtr data, blink::mojom::PerProcessV8MemoryUsageDataPtr data,
RenderProcessHostId expected_process_id = kTestProcessID) { RenderProcessHostId expected_process_id = kTestProcessID,
MockV8PerFrameMemoryReporter::Mode expected_mode =
MockV8PerFrameMemoryReporter::Mode::DEFAULT) {
// Wrap the move-only |data| in a callback for the expectation below. // Wrap the move-only |data| in a callback for the expectation below.
ExpectQueryAndReply(mock_reporter, std::move(data)); ExpectQueryAndReply(mock_reporter, std::move(data), expected_mode);
EXPECT_CALL(*this, BindReceiverWithProxyHost(_, _)) EXPECT_CALL(*this, BindReceiverWithProxyHost(_, _))
.WillOnce( .WillOnce(
...@@ -560,6 +570,35 @@ TEST_F(V8PerFrameMemoryDecoratorTest, PerFrameDataIsDistributed) { ...@@ -560,6 +570,35 @@ TEST_F(V8PerFrameMemoryDecoratorTest, PerFrameDataIsDistributed) {
->unassociated_v8_bytes_used()); ->unassociated_v8_bytes_used());
} }
TEST_F(V8PerFrameMemoryDecoratorTest, LazyRequests) {
V8PerFrameMemoryRequest lazy_request(
kMinTimeBetweenRequests, V8PerFrameMemoryRequest::MeasurementMode::kLazy,
graph());
MockV8PerFrameMemoryReporter reporter;
{
auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
ExpectBindAndRespondToQuery(&reporter, std::move(data), kTestProcessID,
MockV8PerFrameMemoryReporter::Mode::LAZY);
}
auto process = CreateNode<ProcessNodeImpl>(
content::PROCESS_TYPE_RENDERER,
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
task_env().RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(&reporter);
// Bounded requests should be preferred over lazy requests with the same
// min_time_between_requests.
V8PerFrameMemoryRequest bounded_request(kMinTimeBetweenRequests, graph());
auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph());
ASSERT_TRUE(decorator);
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(decorator->GetNextRequest()->mode(),
V8PerFrameMemoryRequest::MeasurementMode::kBounded);
}
TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Create some queries with different sample frequencies. // Create some queries with different sample frequencies.
constexpr base::TimeDelta kShortInterval(kMinTimeBetweenRequests); constexpr base::TimeDelta kShortInterval(kMinTimeBetweenRequests);
...@@ -602,7 +641,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -602,7 +641,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
->unassociated_v8_bytes_used()); ->unassociated_v8_bytes_used());
// Another measurement should be taken after the shortest interval. // Another measurement should be taken after the shortest interval.
EXPECT_EQ(kShortInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kShortInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
data->unassociated_bytes_used = 2U; data->unassociated_bytes_used = 2U;
...@@ -616,7 +657,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -616,7 +657,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Remove the shortest request. Now a measurement should be taken after the // Remove the shortest request. Now a measurement should be taken after the
// medium interval, which is twice the short interval. // medium interval, which is twice the short interval.
short_memory_request.reset(); short_memory_request.reset();
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
data->unassociated_bytes_used = 3U; data->unassociated_bytes_used = 3U;
...@@ -633,7 +676,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -633,7 +676,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Remove the longest request. A measurement should still be taken after the // Remove the longest request. A measurement should still be taken after the
// medium interval. // medium interval.
long_memory_request.reset(); long_memory_request.reset();
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
data->unassociated_bytes_used = 4U; data->unassociated_bytes_used = 4U;
...@@ -646,7 +691,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -646,7 +691,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Remove the medium request, making the queue empty. // Remove the medium request, making the queue empty.
medium_memory_request.reset(); medium_memory_request.reset();
EXPECT_TRUE(decorator->GetMinTimeBetweenRequestsPerProcess().is_zero()); EXPECT_FALSE(decorator->GetNextRequest());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
data->unassociated_bytes_used = 5U; data->unassociated_bytes_used = 5U;
...@@ -661,7 +706,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -661,7 +706,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// the measurement should be taken immediately. // the measurement should be taken immediately.
long_memory_request = long_memory_request =
std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph()); std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph());
EXPECT_EQ(kLongInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kLongInterval,
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(base::TimeDelta::FromSeconds(1)); task_env().FastForwardBy(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(5U, V8PerFrameMemoryProcessData::ForProcessNode(process.get()) EXPECT_EQ(5U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
...@@ -682,7 +729,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -682,7 +729,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// measurement and the old interval should not). // measurement and the old interval should not).
medium_memory_request = medium_memory_request =
std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph()); std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
...@@ -713,10 +762,14 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -713,10 +762,14 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Remove the medium request and add it back. The measurement interval should // Remove the medium request and add it back. The measurement interval should
// not change. // not change.
medium_memory_request.reset(); medium_memory_request.reset();
EXPECT_EQ(kLongInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kLongInterval,
decorator->GetNextRequest()->min_time_between_requests());
medium_memory_request = medium_memory_request =
std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph()); std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
...@@ -732,7 +785,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -732,7 +785,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// interval. // interval.
auto long_memory_request2 = auto long_memory_request2 =
std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph()); std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph());
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
...@@ -747,7 +802,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -747,7 +802,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Remove the medium request. Now there are 2 requests which should cause // Remove the medium request. Now there are 2 requests which should cause
// measurements at the same interval. Make sure only 1 measurement is taken. // measurements at the same interval. Make sure only 1 measurement is taken.
medium_memory_request.reset(); medium_memory_request.reset();
EXPECT_EQ(kLongInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kLongInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
...@@ -761,7 +818,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) { ...@@ -761,7 +818,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Remove 1 of the 2 long requests. Measurements should not change. // Remove 1 of the 2 long requests. Measurements should not change.
long_memory_request2.reset(); long_memory_request2.reset();
EXPECT_EQ(kLongInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kLongInterval,
decorator->GetNextRequest()->min_time_between_requests());
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
...@@ -806,8 +865,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) { ...@@ -806,8 +865,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
// measurement is expected. // measurement is expected.
// Advance to the middle of a measurement and create a new request. Should // Advance to the middle of a measurement and create a new request. Should
// update GetMinTimeBetweenRequestsPerProcess but not start a new // update min_time_between_requests but not start a new measurement until the
// measurement until the existing measurement finishes. // existing measurement finishes.
{ {
auto data = blink::mojom::PerProcessV8MemoryUsageData::New(); auto data = blink::mojom::PerProcessV8MemoryUsageData::New();
data->unassociated_bytes_used = 1U; data->unassociated_bytes_used = 1U;
...@@ -824,7 +883,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) { ...@@ -824,7 +883,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
auto medium_memory_request = auto medium_memory_request =
std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph()); std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(kMeasurementLength); task_env().FastForwardBy(kMeasurementLength);
ASSERT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process.get()) ASSERT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used()) ->unassociated_v8_bytes_used())
...@@ -871,7 +932,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) { ...@@ -871,7 +932,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
auto short_memory_request = auto short_memory_request =
std::make_unique<V8PerFrameMemoryRequest>(kShortInterval, graph()); std::make_unique<V8PerFrameMemoryRequest>(kShortInterval, graph());
EXPECT_EQ(kShortInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kShortInterval,
decorator->GetNextRequest()->min_time_between_requests());
EXPECT_EQ(last_query_time_, measurement_start_time); EXPECT_EQ(last_query_time_, measurement_start_time);
{ {
...@@ -888,11 +951,12 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) { ...@@ -888,11 +951,12 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
<< "Measurement ended early"; << "Measurement ended early";
measurement_start_time = last_query_time_; measurement_start_time = last_query_time_;
// Delete the short request. Should update // Delete the short request. Should update min_time_between_requests but not
// GetMinTimeBetweenRequestsPerProcess but not start a new measurement // start a new measurement until the existing measurement finishes.
// until the existing measurement finishes.
short_memory_request.reset(); short_memory_request.reset();
EXPECT_EQ(kMediumInterval, decorator->GetMinTimeBetweenRequestsPerProcess()); ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(kMeasurementLength); task_env().FastForwardBy(kMeasurementLength);
EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get()) EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used()) ->unassociated_v8_bytes_used())
...@@ -917,7 +981,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) { ...@@ -917,7 +981,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
medium_memory_request.reset(); medium_memory_request.reset();
long_memory_request.reset(); long_memory_request.reset();
EXPECT_TRUE(decorator->GetMinTimeBetweenRequestsPerProcess().is_zero()); EXPECT_FALSE(decorator->GetNextRequest());
task_env().FastForwardBy(kMeasurementLength); task_env().FastForwardBy(kMeasurementLength);
EXPECT_EQ(5U, V8PerFrameMemoryProcessData::ForProcessNode(process.get()) EXPECT_EQ(5U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used()) ->unassociated_v8_bytes_used())
...@@ -1180,8 +1244,9 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) { ...@@ -1180,8 +1244,9 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
FROM_HERE, base::BindOnce([](Graph* graph) { FROM_HERE, base::BindOnce([](Graph* graph) {
auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph); auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph);
ASSERT_TRUE(decorator); ASSERT_TRUE(decorator);
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests, EXPECT_EQ(V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests,
decorator->GetMinTimeBetweenRequestsPerProcess()); decorator->GetNextRequest()->min_time_between_requests());
})); }));
// The observer should be invoked on the main sequence when a measurement is // The observer should be invoked on the main sequence when a measurement is
...@@ -1216,9 +1281,11 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) { ...@@ -1216,9 +1281,11 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
// scheduled tasks, which resets the request frequency to zero. // scheduled tasks, which resets the request frequency to zero.
PerformanceManager::CallOnGraph( PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce([](Graph* graph) { FROM_HERE, base::BindOnce([](Graph* graph) {
auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph);
ASSERT_TRUE(decorator);
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests, EXPECT_EQ(V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests,
V8PerFrameMemoryDecorator::GetFromGraph(graph) decorator->GetNextRequest()->min_time_between_requests());
->GetMinTimeBetweenRequestsPerProcess());
})); }));
// Must remove the observer before destroying the request to avoid a DCHECK // Must remove the observer before destroying the request to avoid a DCHECK
...@@ -1228,9 +1295,9 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) { ...@@ -1228,9 +1295,9 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
PerformanceManager::CallOnGraph( PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce([](Graph* graph) { FROM_HERE, base::BindOnce([](Graph* graph) {
EXPECT_TRUE(V8PerFrameMemoryDecorator::GetFromGraph(graph) auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph);
->GetMinTimeBetweenRequestsPerProcess() ASSERT_TRUE(decorator);
.is_zero()); EXPECT_FALSE(decorator->GetNextRequest());
})); }));
// Execute the above tasks and exit. // Execute the above tasks and exit.
......
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