blob: e0e8791fe9f9c81babe85dcaa8f07018756803d8 [file]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/gpu/peak_gpu_memory_tracker_impl.h"
#include <memory>
#include "base/bind.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/public/browser/gpu_data_manager.h"
#include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
namespace content {
namespace {
// Callback provided to the GpuService, which will be notified of the
// |peak_memory| used. This will then report that to UMA Histograms, for the
// requested |usage|. Some tests may provide an optional |testing_callback| in
// order to sync tests with the work done here on the IO thread.
void PeakMemoryCallback(PeakGpuMemoryTracker::Usage usage,
base::OnceClosure testing_callback,
const uint64_t peak_memory) {
uint64_t memory_in_kb = peak_memory / 1024u;
switch (usage) {
case PeakGpuMemoryTracker::Usage::CHANGE_TAB:
UMA_HISTOGRAM_MEMORY_KB("Memory.GPU.PeakMemoryUsage.ChangeTab",
memory_in_kb);
break;
case PeakGpuMemoryTracker::Usage::PAGE_LOAD:
UMA_HISTOGRAM_MEMORY_KB("Memory.GPU.PeakMemoryUsage.PageLoad",
memory_in_kb);
break;
case PeakGpuMemoryTracker::Usage::SCROLL:
UMA_HISTOGRAM_MEMORY_KB("Memory.GPU.PeakMemoryUsage.Scroll",
memory_in_kb);
break;
}
std::move(testing_callback).Run();
}
} // namespace
// static
std::unique_ptr<PeakGpuMemoryTracker> PeakGpuMemoryTracker::Create(
PeakGpuMemoryTracker::Usage usage) {
return std::make_unique<PeakGpuMemoryTrackerImpl>(usage);
}
// static
uint32_t PeakGpuMemoryTrackerImpl::next_sequence_number_ = 0;
PeakGpuMemoryTrackerImpl::PeakGpuMemoryTrackerImpl(
PeakGpuMemoryTracker::Usage usage)
: usage_(usage) {
// Actually performs request to GPU service to begin memory tracking for
// |sequence_number_|. This will normally be created from the UI thread, so
// repost to the IO thread.
GpuProcessHost::CallOnIO(
GPU_PROCESS_KIND_SANDBOXED, /* force_create=*/false,
base::BindOnce(
[](uint32_t sequence_num, GpuProcessHost* host) {
// There may be no host nor service available. This may occur during
// shutdown, when the service is fully disabled, and in some tests.
// In those cases do nothing.
if (!host)
return;
if (auto* gpu_service = host->gpu_service()) {
gpu_service->StartPeakMemoryMonitor(sequence_num);
}
},
sequence_num_));
}
PeakGpuMemoryTrackerImpl::~PeakGpuMemoryTrackerImpl() {
if (canceled_)
return;
GpuProcessHost::CallOnIO(
GPU_PROCESS_KIND_SANDBOXED, /* force_create=*/false,
base::BindOnce(
[](uint32_t sequence_num, PeakGpuMemoryTracker::Usage usage,
base::OnceClosure testing_callback, GpuProcessHost* host) {
// There may be no host nor service available. This may occur during
// shutdown, when the service is fully disabled, and in some tests.
// In those cases there is nothing to report to UMA. However we
// still run the optional testing callback.
if (!host) {
std::move(testing_callback).Run();
return;
}
if (auto* gpu_service = host->gpu_service()) {
gpu_service->GetPeakMemoryUsage(
sequence_num, base::BindOnce(&PeakMemoryCallback, usage,
std::move(testing_callback)));
}
},
sequence_num_, usage_,
std::move(post_gpu_service_callback_for_testing_)));
}
void PeakGpuMemoryTrackerImpl::Cancel() {
canceled_ = true;
// Notify the GpuProcessHost that we are done observing this sequence.
GpuProcessHost::CallOnIO(GPU_PROCESS_KIND_SANDBOXED, /* force_create=*/false,
base::BindOnce(
[](uint32_t sequence_num, GpuProcessHost* host) {
if (!host)
return;
if (auto* gpu_service = host->gpu_service())
gpu_service->GetPeakMemoryUsage(
sequence_num, base::DoNothing());
},
sequence_num_));
}
} // namespace content