blob: a56d68a07998c1bc2666b0aff8b424832169ff94 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/resource_coordinator/render_process_probe.h"
#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/task/post_task.h"
#include "base/test/metrics/histogram_tester.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace resource_coordinator {
namespace {
class TestingRenderProcessProbe : public RenderProcessProbeImpl {
public:
// Expose for testing.
using RenderProcessProbeImpl::MeasurementOutcome;
void SetMeasurementResults(
bool global_success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump) {
global_success_ = global_success;
dump_ = std::move(dump);
}
protected:
bool global_success_;
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump_;
// Overridden for testing.
void RegisterRenderProcesses() override;
void StartMemoryMeasurement(base::TimeTicks collection_start_time) override;
base::ProcessId GetProcessId(int host_id,
const RenderProcessInfo& info) override;
};
void TestingRenderProcessProbe::RegisterRenderProcesses() {
// Register 4 renderer processes, all of which refer to this process.
for (int id = 1; id < 5; ++id) {
auto& render_process_info = render_process_info_map_[id];
render_process_info.last_gather_cycle_active = current_gather_cycle_;
render_process_info.process = base::Process::Current();
render_process_info.metrics =
base::ProcessMetrics::CreateCurrentProcessMetrics();
}
}
void TestingRenderProcessProbe::StartMemoryMeasurement(
base::TimeTicks collection_start_time) {
// Post the stored results to the completion function.
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&TestingRenderProcessProbe::
ProcessGlobalMemoryDumpAndDispatchOnIOThread,
base::Unretained(this), collection_start_time,
global_success_, std::move(dump_)));
}
base::ProcessId TestingRenderProcessProbe::GetProcessId(
int host_id,
const RenderProcessInfo& /* info */) {
// Use the host ID for PID for the purposes of this test.
return static_cast<base::ProcessId>(host_id);
}
class RenderProcessProbeTest : public testing::Test {
protected:
void RunGatherCycle(
bool global_success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump);
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> CreateMemoryDump(
int first_pid,
int num_pids);
content::TestBrowserThreadBundle browser_thread_bundle_;
TestingRenderProcessProbe probe_;
};
void RenderProcessProbeTest::RunGatherCycle(
bool global_success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump) {
probe_.SetMeasurementResults(global_success, std::move(dump));
probe_.StartSingleGather();
browser_thread_bundle_.RunUntilIdle();
}
std::unique_ptr<memory_instrumentation::GlobalMemoryDump>
RenderProcessProbeTest::CreateMemoryDump(int first_pid, int num_pids) {
memory_instrumentation::mojom::GlobalMemoryDumpPtr global_dump =
memory_instrumentation::mojom::GlobalMemoryDump::New();
for (int pid = first_pid; pid < first_pid + num_pids; ++pid) {
memory_instrumentation::mojom::ProcessMemoryDumpPtr process_dump =
memory_instrumentation::mojom::ProcessMemoryDump::New();
process_dump->os_dump = memory_instrumentation::mojom::OSMemDump::New();
process_dump->os_dump->private_footprint_kb = pid * 100;
process_dump->process_type =
memory_instrumentation::mojom::ProcessType::RENDERER;
process_dump->pid = pid;
global_dump->process_dumps.push_back(std::move(process_dump));
}
return memory_instrumentation::GlobalMemoryDump::MoveFrom(
std::move(global_dump));
}
} // namespace
TEST_F(RenderProcessProbeTest, FailureMetrics) {
base::HistogramTester tester;
// Full failure with a null dump.
RunGatherCycle(false, nullptr);
tester.ExpectTotalCount("ResourceCoordinator.Measurement.Duration", 1);
tester.ExpectUniqueSample("ResourceCoordinator.Measurement.TotalProcesses", 4,
1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.Outcome",
TestingRenderProcessProbe::MeasurementOutcome::kMeasurementFailure, 1);
tester.ExpectTotalCount(
"ResourceCoordinator.Measurement.Memory.UnmeasuredProcesses", 0);
tester.ExpectTotalCount(
"ResourceCoordinator.Measurement.Memory.ExtraProcesses", 0);
}
TEST_F(RenderProcessProbeTest, PartialSuccessMetrics) {
base::HistogramTester tester;
// Partial failure with a full dump.
RunGatherCycle(false, CreateMemoryDump(1, 4));
tester.ExpectTotalCount("ResourceCoordinator.Measurement.Duration", 1);
tester.ExpectUniqueSample("ResourceCoordinator.Measurement.TotalProcesses", 4,
1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.Outcome",
TestingRenderProcessProbe::MeasurementOutcome::kMeasurementPartialSuccess,
1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.UnmeasuredProcesses", 0, 1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.ExtraProcesses", 0, 1);
}
TEST_F(RenderProcessProbeTest, SuccessMetrics) {
base::HistogramTester tester;
// Full success with a skewed dump, missing one process while contributing
// an extra.
RunGatherCycle(true, CreateMemoryDump(2, 4));
tester.ExpectTotalCount("ResourceCoordinator.Measurement.Duration", 1);
tester.ExpectUniqueSample("ResourceCoordinator.Measurement.TotalProcesses", 4,
1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.Outcome",
TestingRenderProcessProbe::MeasurementOutcome::kMeasurementSuccess, 1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.UnmeasuredProcesses", 1, 1);
tester.ExpectUniqueSample(
"ResourceCoordinator.Measurement.Memory.ExtraProcesses", 1, 1);
}
} // namespace resource_coordinator