Commit 3a30e747 authored by Joe Mason's avatar Joe Mason Committed by Chromium LUCI CQ

[PM] Split unassociated bytes into detached and shared bytes

Currently all unassociated bytes are lumped together into one counter.

There are actually two types of unassociated bytes:
- bytes of detached V8 contexts (i.e. contexts not attached to the
  frame tree.
- bytes shared between all V8 contexts.

Besides splitting the bytes, this CL also adds the corresponding
memory types and reports them in the web memory API.

Based on this patch by ulan@chromium.org:
https://chromium-review.googlesource.com/c/chromium/src/+/2626662

Bug: 1085129
Change-Id: I0097e3b1728f5cbfe72746f0a1fd804215487237
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2626978
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: default avatarUlan Degenbaev <ulan@chromium.org>
Auto-Submit: Joe Mason <joenotcharles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843432}
parent c680219e
......@@ -63,7 +63,6 @@ struct WebMemoryBreakdownEntry {
WebMemoryUsage? memory;
array<WebMemoryAttribution> attribution;
// TODO(1085129): Add memory types once they are implemented.
};
// The result of the MeasureMemory function.
......@@ -75,5 +74,14 @@ struct WebMemoryMeasurement {
kDefault,
kEager
};
// A breakdown of memory used for all ExecutionContexts that were measured.
array<WebMemoryBreakdownEntry> breakdown;
// Memory that is used by V8 contexts that are no longer attached to any
// ExecutionContext.
WebMemoryUsage? detached_memory;
// Memory that is not associated with any particular V8 context.
WebMemoryUsage? shared_memory;
};
......@@ -77,8 +77,11 @@ namespace v8_memory {
// const V8DetailedMemoryProcessData* data) override {
// DCHECK(data);
// LOG(INFO) << "Process " << process_node->GetProcessId() <<
// " reported " << data->unassociated_v8_bytes_used() <<
// " reported " << data->detached_v8_bytes_used() <<
// " bytes of V8 memory that wasn't associated with a frame.";
// LOG(INFO) << "Process " << process_node->GetProcessId() <<
// " reported " << data->shared_v8_bytes_used() <<
// " bytes of V8 memory that are shared between all frames";
// for (auto* frame_node : process_node->GetFrameNodes()) {
// auto* frame_data =
// V8DetailedMemoryExecutionContextData::ForFrame(frame_node);
......@@ -142,8 +145,11 @@ namespace v8_memory {
// return;
// }
// LOG(INFO) << "Process " << process->GetID() <<
// " reported " << process_data.unassociated_v8_bytes_used() <<
// " reported " << process_data.detached_v8_bytes_used() <<
// " bytes of V8 memory that wasn't associated with a frame.";
// LOG(INFO) << "Process " << process_node->GetProcessId() <<
// " reported " << data->shared_v8_bytes_used() <<
// " bytes of V8 memory that are shared between all frames";
// for (std::pair<
// content::GlobalFrameRoutingId,
// V8DetailedMemoryExecutionContextData
......@@ -323,17 +329,24 @@ class V8DetailedMemoryProcessData {
virtual ~V8DetailedMemoryProcessData() = default;
bool operator==(const V8DetailedMemoryProcessData& other) const {
return unassociated_v8_bytes_used_ == other.unassociated_v8_bytes_used_;
return detached_v8_bytes_used_ == other.detached_v8_bytes_used_ &&
shared_v8_bytes_used_ == other.shared_v8_bytes_used_;
}
// Returns the number of bytes used by V8 at the last measurement in this
// process that could not be attributed to a frame.
uint64_t unassociated_v8_bytes_used() const {
return unassociated_v8_bytes_used_;
uint64_t detached_v8_bytes_used() const { return detached_v8_bytes_used_; }
void set_detached_v8_bytes_used(uint64_t detached_v8_bytes_used) {
detached_v8_bytes_used_ = detached_v8_bytes_used;
}
void set_unassociated_v8_bytes_used(uint64_t unassociated_v8_bytes_used) {
unassociated_v8_bytes_used_ = unassociated_v8_bytes_used;
// Returns the number of bytes used by V8 at the last measurement in this
// process that are shared between all frames.
uint64_t shared_v8_bytes_used() const { return shared_v8_bytes_used_; }
void set_shared_v8_bytes_used(uint64_t shared_v8_bytes_used) {
shared_v8_bytes_used_ = shared_v8_bytes_used;
}
// Returns process data for the given node, or nullptr if no measurement has
......@@ -343,7 +356,8 @@ class V8DetailedMemoryProcessData {
const ProcessNode* node);
private:
uint64_t unassociated_v8_bytes_used_ = 0;
uint64_t detached_v8_bytes_used_ = 0;
uint64_t shared_v8_bytes_used_ = 0;
};
class V8DetailedMemoryObserver : public base::CheckedObserver {
......
......@@ -466,8 +466,9 @@ void NodeAttachedProcessData::OnV8MemoryUsage(
// Distribute the data to the frames.
// If a frame doesn't have corresponding data in the result, clear any data
// it may have had. Any datum in the result that doesn't correspond to an
// existing frame is likewise accured to unassociated usage.
uint64_t unassociated_v8_bytes_used = 0;
// existing frame is likewise accrued to detached bytes.
uint64_t detached_v8_bytes_used = 0;
uint64_t shared_v8_bytes_used = 0;
// Create a mapping from token to execution context usage for the merge below.
std::vector<std::pair<blink::ExecutionContextToken,
......@@ -477,7 +478,8 @@ void NodeAttachedProcessData::OnV8MemoryUsage(
for (auto& entry : isolate->contexts) {
tmp.emplace_back(entry->token, std::move(entry));
}
unassociated_v8_bytes_used += isolate->unassociated_bytes_used;
detached_v8_bytes_used += isolate->detached_bytes_used;
shared_v8_bytes_used += isolate->shared_bytes_used;
}
size_t found_frame_count = tmp.size();
......@@ -522,12 +524,13 @@ void NodeAttachedProcessData::OnV8MemoryUsage(
// Execution context was already consumed.
continue;
}
// Accrue the data for non-existent frames to unassociated bytes.
unassociated_v8_bytes_used += it.second->bytes_used;
// Accrue the data for non-existent frames to detached bytes.
detached_v8_bytes_used += it.second->bytes_used;
}
data_available_ = true;
data_.set_unassociated_v8_bytes_used(unassociated_v8_bytes_used);
data_.set_detached_v8_bytes_used(detached_v8_bytes_used);
data_.set_shared_v8_bytes_used(shared_v8_bytes_used);
// Schedule another measurement for this process node unless one is already
// scheduled.
......@@ -1016,8 +1019,9 @@ base::Value V8DetailedMemoryDecorator::DescribeProcessNodeData(
DCHECK_EQ(content::PROCESS_TYPE_RENDERER, process_node->GetProcessType());
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetIntKey("unassociated_v8_bytes_used",
process_data->unassociated_v8_bytes_used());
dict.SetIntKey("detached_v8_bytes_used",
process_data->detached_v8_bytes_used());
dict.SetIntKey("shared_v8_bytes_used", process_data->shared_v8_bytes_used());
return dict;
}
......
......@@ -45,7 +45,8 @@ using ::testing::InSequence;
using ::testing::Mock;
using ::testing::StrictMock;
constexpr uint64_t kUnassociatedBytes = 0xABBA;
constexpr uint64_t kDetachedBytes = 0xDEED;
constexpr uint64_t kSharedBytes = 0xABBA;
namespace {
......@@ -57,17 +58,15 @@ class LenientMockV8DetailedMemoryObserver : public V8DetailedMemoryObserver {
const V8DetailedMemoryProcessData* process_data),
(override));
void ExpectObservationOnProcess(
const ProcessNode* process_node,
uint64_t expected_unassociated_v8_bytes_used) {
void ExpectObservationOnProcess(const ProcessNode* process_node,
uint64_t expected_shared_v8_bytes_used) {
using ::testing::Eq;
using ::testing::Property;
EXPECT_CALL(
*this,
EXPECT_CALL(*this,
OnV8MemoryMeasurementAvailable(
process_node,
Property(&V8DetailedMemoryProcessData::unassociated_v8_bytes_used,
Eq(expected_unassociated_v8_bytes_used))));
Property(&V8DetailedMemoryProcessData::shared_v8_bytes_used,
Eq(expected_shared_v8_bytes_used))));
}
};
......@@ -163,7 +162,8 @@ TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnEmptyGraph) {
MockV8DetailedMemoryReporter mock_reporter;
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = kUnassociatedBytes;
data->isolates[0]->detached_bytes_used = kDetachedBytes;
data->isolates[0]->shared_bytes_used = kSharedBytes;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
// Create a process node and validate that it gets a request.
......@@ -178,9 +178,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnEmptyGraph) {
task_env().RunUntilIdle();
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(kUnassociatedBytes,
EXPECT_EQ(kDetachedBytes,
V8DetailedMemoryProcessData::ForProcessNode(process.get())
->detached_v8_bytes_used());
EXPECT_EQ(kSharedBytes,
V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnNonEmptyGraph) {
......@@ -192,7 +195,8 @@ TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnNonEmptyGraph) {
MockV8DetailedMemoryReporter mock_reporter;
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = kUnassociatedBytes;
data->isolates[0]->detached_bytes_used = kDetachedBytes;
data->isolates[0]->shared_bytes_used = kSharedBytes;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
......@@ -204,9 +208,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnNonEmptyGraph) {
task_env().RunUntilIdle();
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(kUnassociatedBytes,
EXPECT_EQ(kDetachedBytes,
V8DetailedMemoryProcessData::ForProcessNode(process.get())
->detached_v8_bytes_used());
EXPECT_EQ(kSharedBytes,
V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
TEST_F(V8DetailedMemoryDecoratorTest, OnlyMeasureRenderers) {
......@@ -250,13 +257,13 @@ TEST_F(V8DetailedMemoryDecoratorTest, OneShot) {
MockV8DetailedMemoryReporter mock_reporter1;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1ULL;
data->isolates[0]->shared_bytes_used = 1ULL;
ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data), kProcessId1);
}
MockV8DetailedMemoryReporter mock_reporter2;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2ULL;
data->isolates[0]->shared_bytes_used = 2ULL;
ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data), kProcessId2);
}
......@@ -268,26 +275,26 @@ TEST_F(V8DetailedMemoryDecoratorTest, OneShot) {
// called only for that process.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3ULL;
data->isolates[0]->shared_bytes_used = 3ULL;
ExpectQueryAndReply(&mock_reporter1, std::move(data));
}
uint64_t unassociated_v8_bytes_used = 0;
uint64_t shared_v8_bytes_used = 0;
V8DetailedMemoryRequestOneShot process1_request;
process1_request.StartMeasurement(
process1.get(), base::BindLambdaForTesting(
[&unassociated_v8_bytes_used, &process1](
[&shared_v8_bytes_used, &process1](
const ProcessNode* process_node,
const V8DetailedMemoryProcessData* process_data) {
ASSERT_TRUE(process_data);
EXPECT_EQ(process_node, process1.get());
unassociated_v8_bytes_used =
process_data->unassociated_v8_bytes_used();
shared_v8_bytes_used =
process_data->shared_v8_bytes_used();
}));
task_env().RunUntilIdle();
Mock::VerifyAndClearExpectations(&mock_reporter1);
Mock::VerifyAndClearExpectations(&mock_reporter2);
EXPECT_EQ(unassociated_v8_bytes_used, 3ULL);
EXPECT_EQ(shared_v8_bytes_used, 3ULL);
}
TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetime) {
......@@ -301,7 +308,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetime) {
ExpectBindReceiver(&mock_reporter);
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1ULL;
data->isolates[0]->shared_bytes_used = 1ULL;
ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
std::move(data));
}
......@@ -325,28 +332,28 @@ TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetime) {
// sure nothing explodes.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2ULL;
data->isolates[0]->shared_bytes_used = 2ULL;
ExpectQueryAndReply(&mock_reporter, std::move(data));
}
uint64_t unassociated_v8_bytes_used = 0;
uint64_t shared_v8_bytes_used = 0;
doomed_request = std::make_unique<V8DetailedMemoryRequestOneShot>(
process.get(), base::BindLambdaForTesting(
[&](const ProcessNode* process_node,
const V8DetailedMemoryProcessData* process_data) {
doomed_request.reset();
ASSERT_TRUE(process_data);
unassociated_v8_bytes_used =
process_data->unassociated_v8_bytes_used();
shared_v8_bytes_used =
process_data->shared_v8_bytes_used();
}));
task_env().RunUntilIdle();
Mock::VerifyAndClearExpectations(&mock_reporter);
EXPECT_EQ(unassociated_v8_bytes_used, 2ULL);
EXPECT_EQ(shared_v8_bytes_used, 2ULL);
// Ensure that resource-owning callbacks are freed when there is no response
// because the process dies.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3ULL;
data->isolates[0]->shared_bytes_used = 3ULL;
ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
std::move(data));
}
......@@ -387,7 +394,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetimeAtExit) {
ExpectBindReceiver(&mock_reporter);
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1ULL;
data->isolates[0]->shared_bytes_used = 1ULL;
ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
std::move(data));
}
......@@ -425,7 +432,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
{
auto data = NewPerProcessV8MemoryUsage(1);
// Response to request 1.
data->isolates[0]->unassociated_bytes_used = 1;
data->isolates[0]->shared_bytes_used = 1;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
}
......@@ -436,7 +443,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(1u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// There shouldn't be an additional request this soon.
task_env().FastForwardBy(kMinTimeBetweenRequests / 2);
......@@ -463,13 +470,13 @@ TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(1u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Expect another query once completing the query above.
{
auto data = NewPerProcessV8MemoryUsage(1);
// Response to request 3.
data->isolates[0]->unassociated_bytes_used = 3;
data->isolates[0]->shared_bytes_used = 3;
ExpectQueryAndReply(&mock_reporter, std::move(data));
}
......@@ -477,7 +484,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
{
auto data = NewPerProcessV8MemoryUsage(1);
// Response to request 2.
data->isolates[0]->unassociated_bytes_used = 2;
data->isolates[0]->shared_bytes_used = 2;
std::move(callback).Run(std::move(data));
}
......@@ -486,7 +493,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
// This should have updated all the way to the third response.
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(3u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Despite the long delay to respond to request 2, there shouldn't be another
// request until kMinTimeBetweenRequests has expired.
......@@ -501,7 +508,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
MockV8DetailedMemoryReporter reporter1;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1;
data->isolates[0]->shared_bytes_used = 1;
ExpectBindAndRespondToQuery(&reporter1, std::move(data));
}
......@@ -516,7 +523,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
MockV8DetailedMemoryReporter reporter2;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2;
data->isolates[0]->shared_bytes_used = 2;
ExpectBindAndRespondToQuery(&reporter2, std::move(data));
}
......@@ -529,10 +536,10 @@ TEST_F(V8DetailedMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
EXPECT_EQ(1u, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process2.get()));
EXPECT_EQ(2u, V8DetailedMemoryProcessData::ForProcessNode(process2.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Capture the request time from each process.
auto capture_time_lambda =
......@@ -619,10 +626,10 @@ TEST_F(V8DetailedMemoryDecoratorTest, DataIsDistributed) {
task_env().RunUntilIdle();
Mock::VerifyAndClearExpectations(&reporter);
// Since the frame was unknown, the usage should have accrued to unassociated.
// Since the frame was unknown, the usage should have accrued to detached.
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(1024u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->detached_v8_bytes_used());
// Create a couple of frames with specified IDs.
auto page = CreateNode<PageNodeImpl>();
......@@ -654,7 +661,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, DataIsDistributed) {
->v8_bytes_used());
// Now verify that data is cleared for any frame that doesn't get an update,
// plus verify that unknown frame data toes to unassociated bytes.
// plus verify that unknown frame data goes to detached bytes.
{
auto data = NewPerProcessV8MemoryUsage(1);
AddIsolateMemoryUsage(frame1_id, 1003u, data->isolates[0].get());
......@@ -673,7 +680,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, DataIsDistributed) {
V8DetailedMemoryExecutionContextData::ForFrameNode(frame2.get()));
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(2233u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->detached_v8_bytes_used());
}
TEST_P(V8DetailedMemoryDecoratorModeTest, LazyRequests) {
......@@ -713,7 +720,7 @@ TEST_P(V8DetailedMemoryDecoratorModeTest, LazyRequests) {
// until reply arrives. kLongBoundedRequestLength > 40 sec so the reply
// should arrive in time to prevent upgrading the request.
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectQueryAndDelayReply(&reporter, base::TimeDelta::FromSeconds(10),
std::move(data), ExpectedMode::LAZY);
}
......@@ -738,12 +745,12 @@ TEST_P(V8DetailedMemoryDecoratorModeTest, LazyRequests) {
// Again, 40 sec total until reply arrives. kUpgradeRequestLength <= 40 sec
// so a second upgraded request should be sent.
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectQueryAndDelayReply(&reporter, base::TimeDelta::FromSeconds(10),
std::move(data), ExpectedMode::LAZY);
auto data2 = NewPerProcessV8MemoryUsage(1);
data2->isolates[0]->unassociated_bytes_used = 3U;
data2->isolates[0]->shared_bytes_used = 3U;
ExpectQueryAndReply(&reporter, std::move(data2), expected_bounded_mode_);
}
......@@ -753,7 +760,7 @@ TEST_P(V8DetailedMemoryDecoratorModeTest, LazyRequests) {
EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(3u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Bounded requests should be preferred over lazy requests with the same
// min_time_between_requests.
......@@ -797,7 +804,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
MockV8DetailedMemoryReporter mock_reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
}
......@@ -812,7 +819,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Another measurement should be taken after the shortest interval.
ASSERT_TRUE(decorator->GetNextRequest());
......@@ -820,12 +827,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
decorator->GetNextRequest()->min_time_between_requests());
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kShortInterval);
EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Remove the shortest request. Now a measurement should be taken after the
......@@ -836,15 +843,15 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
decorator->GetNextRequest()->min_time_between_requests());
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3U;
data->isolates[0]->shared_bytes_used = 3U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kShortInterval);
EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
task_env().FastForwardBy(kShortInterval);
EXPECT_EQ(3U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Remove the longest request. A measurement should still be taken after the
......@@ -855,12 +862,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
decorator->GetNextRequest()->min_time_between_requests());
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 4U;
data->isolates[0]->shared_bytes_used = 4U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Remove the medium request, making the queue empty.
......@@ -868,12 +875,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
EXPECT_FALSE(decorator->GetNextRequest());
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 5U;
data->isolates[0]->shared_bytes_used = 5U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Create another request. Since this is the first request in an empty queue
......@@ -886,16 +893,16 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
task_env().FastForwardBy(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(5U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 6U;
data->isolates[0]->shared_bytes_used = 6U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
EXPECT_EQ(6U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Now there should be kLongInterval - 1 sec until the next measurement.
......@@ -909,28 +916,28 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 7U;
data->isolates[0]->shared_bytes_used = 7U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
EXPECT_EQ(7U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 8U;
data->isolates[0]->shared_bytes_used = 8U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
constexpr base::TimeDelta kRestOfLongInterval =
kLongInterval - kMediumInterval;
task_env().FastForwardBy(kRestOfLongInterval);
EXPECT_EQ(7U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
task_env().FastForwardBy(kMediumInterval - kRestOfLongInterval);
EXPECT_EQ(8U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Remove the medium request and add it back. The measurement interval should
......@@ -947,12 +954,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 9U;
data->isolates[0]->shared_bytes_used = 9U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
EXPECT_EQ(9U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Add another long request. There should still be requests after the medium
......@@ -965,12 +972,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 10U;
data->isolates[0]->shared_bytes_used = 10U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
EXPECT_EQ(10U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Remove the medium request. Now there are 2 requests which should cause
......@@ -982,12 +989,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 11U;
data->isolates[0]->shared_bytes_used = 11U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
EXPECT_EQ(11U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
// Remove 1 of the 2 long requests. Measurements should not change.
......@@ -998,12 +1005,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 12U;
data->isolates[0]->shared_bytes_used = 12U;
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
EXPECT_EQ(12U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
}
......@@ -1028,7 +1035,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
MockV8DetailedMemoryReporter mock_reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 0U;
data->isolates[0]->shared_bytes_used = 0U;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
}
auto process = CreateNode<ProcessNodeImpl>(
......@@ -1043,7 +1050,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
// existing measurement finishes.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectQueryAndDelayReply(&mock_reporter, kMeasurementLength,
std::move(data));
}
......@@ -1051,7 +1058,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
EXPECT_EQ(0U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement ended early";
base::TimeTicks measurement_start_time = last_query_time();
......@@ -1062,7 +1069,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(kMeasurementLength);
ASSERT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement didn't end when expected";
EXPECT_EQ(last_query_time(), measurement_start_time);
......@@ -1070,7 +1077,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
// last measurement.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectQueryAndDelayReply(&mock_reporter, kMeasurementLength,
std::move(data));
}
......@@ -1078,13 +1085,13 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
EXPECT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement ended early";
measurement_start_time = last_query_time();
task_env().FastForwardBy(kMeasurementLength);
EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement didn't end when expected";
EXPECT_EQ(last_query_time(), measurement_start_time);
......@@ -1092,7 +1099,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
// should start immediately after the measurement finishes.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3U;
data->isolates[0]->shared_bytes_used = 3U;
ExpectQueryAndDelayReply(&mock_reporter, kMeasurementLength,
std::move(data));
}
......@@ -1100,7 +1107,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement ended early";
measurement_start_time = last_query_time();
......@@ -1113,7 +1120,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 4U;
data->isolates[0]->shared_bytes_used = 4U;
ExpectQueryAndDelayReply(&mock_reporter, kMeasurementLength,
std::move(data));
}
......@@ -1121,7 +1128,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
EXPECT_EQ(3U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement ended early";
measurement_start_time = last_query_time();
......@@ -1133,7 +1140,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(kMeasurementLength);
EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement didn't end when expected";
EXPECT_EQ(last_query_time(), measurement_start_time);
......@@ -1141,7 +1148,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
// measurement should finish successfully but no more should be sent.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 5U;
data->isolates[0]->shared_bytes_used = 5U;
ExpectQueryAndDelayReply(&mock_reporter, kMeasurementLength,
std::move(data));
}
......@@ -1149,7 +1156,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement ended early";
measurement_start_time = last_query_time();
......@@ -1158,7 +1165,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_FALSE(decorator->GetNextRequest());
task_env().FastForwardBy(kMeasurementLength);
EXPECT_EQ(5U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "Measurement didn't end when expected";
EXPECT_EQ(last_query_time(), measurement_start_time);
......@@ -1176,7 +1183,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestOutlivesDecorator) {
MockV8DetailedMemoryReporter mock_reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
}
auto process = CreateNode<ProcessNodeImpl>(
......@@ -1184,7 +1191,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestOutlivesDecorator) {
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
task_env().FastForwardBy(base::TimeDelta::FromSeconds(1));
ASSERT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
->shared_v8_bytes_used())
<< "First measurement didn't happen when expected";
graph()->TakeFromGraph(decorator);
......@@ -1207,7 +1214,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, NotifyObservers) {
MockV8DetailedMemoryReporter reporter1;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&reporter1, std::move(data));
}
......@@ -1229,12 +1236,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, NotifyObservers) {
MockV8DetailedMemoryReporter reporter2;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectBindAndRespondToQuery(&reporter2, std::move(data));
}
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3U;
data->isolates[0]->shared_bytes_used = 3U;
ExpectQueryAndReply(&reporter1, std::move(data));
}
......@@ -1257,12 +1264,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, NotifyObservers) {
// next measurement.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 4U;
data->isolates[0]->shared_bytes_used = 4U;
ExpectQueryAndReply(&reporter1, std::move(data));
}
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 5U;
data->isolates[0]->shared_bytes_used = 5U;
ExpectQueryAndReply(&reporter2, std::move(data));
}
......@@ -1292,7 +1299,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, ObserverOutlivesDecorator) {
MockV8DetailedMemoryReporter reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&reporter, std::move(data));
}
......@@ -1309,7 +1316,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, ObserverOutlivesDecorator) {
// Start the next measurement.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectQueryAndDelayReply(&reporter, kMinTimeBetweenRequests,
std::move(data));
}
......@@ -1353,12 +1360,12 @@ TEST_F(V8DetailedMemoryDecoratorTest, SingleProcessRequest) {
{
// Response to initial request in process 1.
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data), kProcessId1);
// Response to initial request in process 2.
data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data), kProcessId2);
}
......@@ -1370,17 +1377,17 @@ TEST_F(V8DetailedMemoryDecoratorTest, SingleProcessRequest) {
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
EXPECT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process2.get()));
EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process2.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// After kMinTimeBetweenRequests another request should be sent to process1,
// but not process2.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3U;
data->isolates[0]->shared_bytes_used = 3U;
ExpectQueryAndDelayReply(&mock_reporter1, kMinTimeBetweenRequests,
std::move(data));
}
......@@ -1397,13 +1404,13 @@ TEST_F(V8DetailedMemoryDecoratorTest, SingleProcessRequest) {
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
EXPECT_EQ(3U, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Recreate process1 request. The new request will be sent immediately since
// enough time has passed since the last request.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 4U;
data->isolates[0]->shared_bytes_used = 4U;
ExpectQueryAndReply(&mock_reporter1, std::move(data));
}
......@@ -1423,7 +1430,7 @@ TEST_F(V8DetailedMemoryDecoratorTest, SingleProcessRequest) {
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
// Delete process1 while the request still exists. Nothing should crash.
process1.reset();
......@@ -1465,7 +1472,7 @@ TEST_P(V8DetailedMemoryDecoratorSingleProcessModeTest,
// Response to initial request which is sent immediately. This will use the
// LAZY mode from |lazy_request| because it has a lower frequency.
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data), kTestProcessID,
ExpectedMode::LAZY);
}
......@@ -1479,7 +1486,7 @@ TEST_P(V8DetailedMemoryDecoratorSingleProcessModeTest,
// waiting.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3U;
data->isolates[0]->shared_bytes_used = 3U;
ExpectQueryAndDelayReply(&mock_reporter, 2 * kMinTimeBetweenRequests,
std::move(data), ExpectedMode::LAZY);
}
......@@ -1492,7 +1499,7 @@ TEST_P(V8DetailedMemoryDecoratorSingleProcessModeTest,
// should send |bounded_request| to both processes.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 4U;
data->isolates[0]->shared_bytes_used = 4U;
ExpectQueryAndReply(&mock_reporter, std::move(data), ExpectedMode::DEFAULT);
}
......@@ -1501,7 +1508,7 @@ TEST_P(V8DetailedMemoryDecoratorSingleProcessModeTest,
ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
->shared_v8_bytes_used());
}
INSTANTIATE_TEST_SUITE_P(SingleProcessLazyOrBounded,
......@@ -1577,14 +1584,14 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
main_frame()->GetRoutingID());
V8DetailedMemoryProcessData expected_process_data;
expected_process_data.set_unassociated_v8_bytes_used(kUnassociatedBytes);
expected_process_data.set_shared_v8_bytes_used(kSharedBytes);
V8DetailedMemoryObserverAnySeq::FrameDataMap expected_frame_data;
expected_frame_data[frame_id].set_v8_bytes_used(kAssociatedBytes);
MockV8DetailedMemoryReporter reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = kUnassociatedBytes;
data->isolates[0]->shared_bytes_used = kSharedBytes;
AddIsolateMemoryUsage(frame_token, kAssociatedBytes,
data->isolates[0].get());
ExpectBindAndRespondToQuery(&reporter, std::move(data), main_process_id());
......@@ -1676,20 +1683,20 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, SingleProcessRequest) {
CreateCrossProcessChildFrame();
V8DetailedMemoryProcessData expected_process_data1;
expected_process_data1.set_unassociated_v8_bytes_used(1U);
expected_process_data1.set_shared_v8_bytes_used(1U);
V8DetailedMemoryProcessData expected_process_data2;
expected_process_data2.set_unassociated_v8_bytes_used(2U);
expected_process_data2.set_shared_v8_bytes_used(2U);
MockV8DetailedMemoryReporter mock_reporter1;
MockV8DetailedMemoryReporter mock_reporter2;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1U;
data->isolates[0]->shared_bytes_used = 1U;
ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data),
main_process_id());
data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2U;
data->isolates[0]->shared_bytes_used = 2U;
ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data),
child_process_id());
}
......@@ -1743,7 +1750,7 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShot) {
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1ULL;
data->isolates[0]->shared_bytes_used = 1ULL;
ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data),
main_process_id());
}
......@@ -1751,7 +1758,7 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShot) {
MockV8DetailedMemoryReporter mock_reporter2;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2ULL;
data->isolates[0]->shared_bytes_used = 2ULL;
ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data),
child_process_id());
}
......@@ -1764,11 +1771,11 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShot) {
// called only for that process.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3ULL;
data->isolates[0]->shared_bytes_used = 3ULL;
ExpectQueryAndReply(&mock_reporter1, std::move(data));
}
uint64_t unassociated_v8_bytes_used = 0;
uint64_t shared_v8_bytes_used = 0;
V8DetailedMemoryRequestOneShotAnySeq process1_request;
process1_request.StartMeasurement(
main_process_id(),
......@@ -1778,13 +1785,12 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShot) {
const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
frame_data) {
EXPECT_EQ(process_id, main_process_id());
unassociated_v8_bytes_used =
process_data.unassociated_v8_bytes_used();
shared_v8_bytes_used = process_data.shared_v8_bytes_used();
}));
task_environment()->RunUntilIdle();
Mock::VerifyAndClearExpectations(&mock_reporter1);
Mock::VerifyAndClearExpectations(&mock_reporter2);
EXPECT_EQ(unassociated_v8_bytes_used, 3ULL);
EXPECT_EQ(shared_v8_bytes_used, 3ULL);
}
TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetime) {
......@@ -1798,7 +1804,7 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetime) {
ExpectBindReceiver(&mock_reporter, child_process_id());
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1ULL;
data->isolates[0]->shared_bytes_used = 1ULL;
ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
std::move(data));
}
......@@ -1824,10 +1830,10 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetime) {
// sure nothing explodes.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 2ULL;
data->isolates[0]->shared_bytes_used = 2ULL;
ExpectQueryAndReply(&mock_reporter, std::move(data));
}
uint64_t unassociated_v8_bytes_used = 0;
uint64_t shared_v8_bytes_used = 0;
doomed_request = std::make_unique<V8DetailedMemoryRequestOneShotAnySeq>(
child_process_id(),
base::BindLambdaForTesting(
......@@ -1836,18 +1842,17 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetime) {
const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
frame_data) {
doomed_request.reset();
unassociated_v8_bytes_used =
process_data.unassociated_v8_bytes_used();
shared_v8_bytes_used = process_data.shared_v8_bytes_used();
}));
task_environment()->RunUntilIdle();
Mock::VerifyAndClearExpectations(&mock_reporter);
EXPECT_EQ(unassociated_v8_bytes_used, 2ULL);
EXPECT_EQ(shared_v8_bytes_used, 2ULL);
// Ensure that resource-owning callbacks are freed when there is no response
// because the process dies.
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 3ULL;
data->isolates[0]->shared_bytes_used = 3ULL;
ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
std::move(data));
}
......@@ -1885,7 +1890,7 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetimeAtExit) {
ExpectBindReceiver(&mock_reporter, main_process_id());
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = 1ULL;
data->isolates[0]->shared_bytes_used = 1ULL;
ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
std::move(data));
}
......
......@@ -207,6 +207,18 @@ WebMemoryAggregator::AggregateMeasureMemoryResult() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
aggregation_result_ = mojom::WebMemoryMeasurement::New();
VisitFrame(nullptr, aggregation_start_node_);
auto* process_data = V8DetailedMemoryProcessData::ForProcessNode(
aggregation_start_node_->GetProcessNode());
if (process_data) {
aggregation_result_->detached_memory = mojom::WebMemoryUsage::New();
aggregation_result_->detached_memory->bytes =
process_data->detached_v8_bytes_used();
aggregation_result_->shared_memory = mojom::WebMemoryUsage::New();
aggregation_result_->shared_memory->bytes =
process_data->shared_v8_bytes_used();
}
return std::move(aggregation_result_);
}
......
......@@ -14,16 +14,15 @@ struct PerContextV8MemoryUsage {
};
struct PerIsolateV8MemoryUsage {
// The number of V8 heap bytes that were not associated with a specific
// V8 context, most likely because they're shared objects.
uint64 unassociated_bytes_used;
// The number of V8 contexts not associated with an execution context,
// likely web application leaks, and their associated byte usage. At the present time
// (April 2020), it's expected and normal to see one unassociated context per
// renderer process accounting for ~70kB.
uint64 num_unassociated_contexts;
uint64 unassociated_context_bytes_used;
// likely web application leaks, and their associated byte usage.
// Such contexts are known as detached contexts.
uint64 num_detached_contexts;
uint64 detached_bytes_used;
// Bytes shared across all V8 contexts. These bytes are not attributed
// to any particular V8 context.
uint64 shared_bytes_used;
// The V8 memory usage by individual V8 contexts in this process.
array<PerContextV8MemoryUsage> contexts;
......
......@@ -63,8 +63,8 @@ class FrameAssociatedMeasurementDelegate : public v8::MeasureMemoryDelegate {
// TODO(crbug.com/1080672): It would be prefereable to count the
// V8SchemaRegistry context's overhead with unassociated_bytes, but at
// present there isn't a public API that allows this distinction.
++(isolate_memory_usage->num_unassociated_contexts);
isolate_memory_usage->unassociated_context_bytes_used += size;
++(isolate_memory_usage->num_detached_contexts);
isolate_memory_usage->detached_bytes_used += size;
continue;
}
if (DOMWrapperWorld::World(context).GetWorldId() !=
......@@ -85,7 +85,7 @@ class FrameAssociatedMeasurementDelegate : public v8::MeasureMemoryDelegate {
#endif
isolate_memory_usage->contexts.push_back(std::move(context_memory_usage));
}
isolate_memory_usage->unassociated_bytes_used = unattributed_size_in_bytes;
isolate_memory_usage->shared_bytes_used = unattributed_size_in_bytes;
std::move(callback_).Run(std::move(isolate_memory_usage));
}
......
......@@ -34,6 +34,7 @@ using performance_manager::mojom::blink::WebMemoryAttributionPtr;
using performance_manager::mojom::blink::WebMemoryBreakdownEntryPtr;
using performance_manager::mojom::blink::WebMemoryMeasurement;
using performance_manager::mojom::blink::WebMemoryMeasurementPtr;
using performance_manager::mojom::blink::WebMemoryUsagePtr;
namespace blink {
......@@ -180,6 +181,19 @@ MemoryBreakdownEntry* ConvertBreakdown(
return result;
}
MemoryBreakdownEntry* CreateUnattributedBreakdown(
const WebMemoryUsagePtr& memory,
const WTF::String& memory_type) {
auto* result = MemoryBreakdownEntry::Create();
DCHECK(memory);
result->setBytes(memory->bytes);
result->setAttribution({});
Vector<String> types;
types.push_back(memory_type);
result->setTypes(types);
return result;
}
MemoryBreakdownEntry* EmptyBreakdown() {
auto* result = MemoryBreakdownEntry::Create();
result->setBytes(0);
......@@ -195,6 +209,11 @@ MemoryMeasurement* ConvertResult(const WebMemoryMeasurementPtr& measurement) {
if (entry->memory)
breakdown.push_back(ConvertBreakdown(entry));
}
// Add breakdowns for memory that isn't attributed to an execution context.
breakdown.push_back(
CreateUnattributedBreakdown(measurement->detached_memory, "Detached"));
breakdown.push_back(
CreateUnattributedBreakdown(measurement->shared_memory, "Shared"));
// Add an empty breakdown entry as required by the spec.
// See https://github.com/WICG/performance-measure-memory/issues/10.
breakdown.push_back(EmptyBreakdown());
......
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