blob: f075c9ea5c23369cc3869ef78aa5cf86463174b4 [file] [log] [blame]
// Copyright 2020 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 "third_party/blink/renderer/controller/performance_manager/v8_detailed_memory_reporter_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/core/workers/dedicated_worker_test.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "v8/include/v8.h"
namespace blink {
class V8DetailedMemoryReporterImplTest : public SimTest {};
class V8DetailedMemoryReporterImplWorkerTest : public DedicatedWorkerTest {};
namespace {
class MemoryUsageChecker {
public:
enum class CallbackAction { kExitRunLoop, kNone };
MemoryUsageChecker(size_t expected_isolate_count,
size_t expected_context_count)
: expected_isolate_count_(expected_isolate_count),
expected_context_count_(expected_context_count) {}
void Callback(mojom::blink::PerProcessV8MemoryUsagePtr result) {
EXPECT_EQ(expected_isolate_count_, result->isolates.size());
size_t actual_context_count = 0;
for (const auto& isolate : result->isolates) {
for (const auto& entry : isolate->contexts) {
// The memory usage of each context should be at least 1000000 bytes
// because each context allocates a byte array of that length. Since
// other objects are allocated during context initialization we can
// only check the lower bound.
EXPECT_LE(1000000u, entry->bytes_used);
++actual_context_count;
if (entry->token.Is<DedicatedWorkerToken>()) {
EXPECT_EQ(String("http://fake.url/"), entry->url);
} else {
EXPECT_FALSE(entry->url);
}
}
}
EXPECT_EQ(expected_context_count_, actual_context_count);
called_ = true;
test::ExitRunLoop();
}
bool IsCalled() { return called_; }
private:
size_t expected_isolate_count_;
size_t expected_context_count_;
bool called_ = false;
};
} // anonymous namespace
TEST_F(V8DetailedMemoryReporterImplTest, GetV8MemoryUsage) {
SimRequest main_resource("https://example.com/", "text/html");
SimRequest child_frame_resource("https://example.com/subframe.html",
"text/html");
LoadURL("https://example.com/");
main_resource.Complete(R"HTML(
<script>
window.onload = function () {
globalThis.root = {
array: new Uint8Array(1000000)
};
console.log("main loaded");
}
</script>
<body>
<iframe src='https://example.com/subframe.html'></iframe>
</body>)HTML");
test::RunPendingTasks();
child_frame_resource.Complete(R"HTML(
<script>
window.onload = function () {
globalThis.root = {
array: new Uint8Array(1000000)
};
console.log("iframe loaded");
}
</script>
<body>
</body>)HTML");
test::RunPendingTasks();
// Ensure that main frame and subframe are loaded before measuring memory
// usage.
EXPECT_TRUE(ConsoleMessages().Contains("main loaded"));
EXPECT_TRUE(ConsoleMessages().Contains("iframe loaded"));
V8DetailedMemoryReporterImpl reporter;
// We expect to see the main isolate with two contexts corresponding to
// the main page and the iframe.
size_t expected_isolate_count = 1;
size_t expected_context_count = 2;
MemoryUsageChecker checker(expected_isolate_count, expected_context_count);
reporter.GetV8MemoryUsage(
V8DetailedMemoryReporterImpl::Mode::EAGER,
WTF::Bind(&MemoryUsageChecker::Callback, WTF::Unretained(&checker)));
test::EnterRunLoop();
EXPECT_TRUE(checker.IsCalled());
}
TEST_F(V8DetailedMemoryReporterImplWorkerTest, GetV8MemoryUsage) {
const String source_code = R"JS(
globalThis.root = {
array: new Uint8Array(1000000)
};)JS";
StartWorker(source_code);
WaitUntilWorkerIsRunning();
V8DetailedMemoryReporterImpl reporter;
// We expect to see two isolates: the main isolate and the worker isolate.
// Only the worker isolate has a context. The main isolate is empty because
// DedicatedWorkerTest does not set it up.
size_t expected_isolate_count = 2;
size_t expected_context_count = 1;
MemoryUsageChecker checker(expected_isolate_count, expected_context_count);
reporter.GetV8MemoryUsage(
V8DetailedMemoryReporterImpl::Mode::EAGER,
WTF::Bind(&MemoryUsageChecker::Callback, WTF::Unretained(&checker)));
test::EnterRunLoop();
EXPECT_TRUE(checker.IsCalled());
}
} // namespace blink