#include "ash/hud_display/memory_graph_page_view.h"
#include <algorithm>
#include <numeric>
#include <string>
#include "ash/hud_display/hud_constants.h"
#include "ash/hud_display/reference_lines.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/canvas.h"
namespace ash {
namespace hud_display {
BEGIN_METADATA(MemoryGraphPageView, GraphPageViewBase)
END_METADATA
MemoryGraphPageView::MemoryGraphPageView(const base::TimeDelta refresh_interval)
: graph_chrome_rss_private_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
Graph::Style::LINES,
SkColorSetA(SK_ColorRED, kHUDAlpha)),
graph_mem_free_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::NONE,
Graph::Style::LINES,
SkColorSetA(SK_ColorDKGRAY, kHUDAlpha)),
graph_mem_used_unknown_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
Graph::Style::LINES,
SkColorSetA(SK_ColorLTGRAY, kHUDAlpha)),
graph_renderers_rss_private_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
Graph::Style::LINES,
SkColorSetA(SK_ColorCYAN, kHUDAlpha)),
graph_arc_rss_private_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
Graph::Style::LINES,
SkColorSetA(SK_ColorMAGENTA, kHUDAlpha)),
graph_gpu_rss_private_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
Graph::Style::LINES,
SkColorSetA(SK_ColorRED, kHUDAlpha)),
graph_gpu_kernel_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::SOLID,
Graph::Style::LINES,
SkColorSetA(SK_ColorYELLOW, kHUDAlpha)),
graph_chrome_rss_shared_(kHUDGraphWidth,
Graph::Baseline::BASELINE_BOTTOM,
Graph::Fill::NONE,
Graph::Style::LINES,
SkColorSetA(SK_ColorBLUE, kHUDAlpha)) {
const int data_width = graph_arc_rss_private_.max_data_points();
constexpr float vertical_ticks_interval = 10 / 100.0;
reference_lines_ = CreateReferenceLines(
static_cast<int>(-data_width * refresh_interval.InSecondsF()),
0, 0, 0, u"s",
u"Gb",
data_width,
10 / refresh_interval.InSecondsF(),
vertical_ticks_interval);
reference_lines_->SetVisible(false);
Legend::Formatter formatter = base::BindRepeating([](float value) {
return base::ASCIIToUTF16(
base::StringPrintf("%d Mb", std::max(0, (int)(value * 1024))));
});
const std::vector<Legend::Entry> legend({
{graph_gpu_kernel_, u"GPU Driver",
u"Kernel GPU buffers as reported\nby base::SystemMemoryInfo::gem_size.",
formatter},
{graph_gpu_rss_private_, u"Chrome GPU",
u"RSS private memory of\n --type=gpu-process Chrome process.",
formatter},
{graph_renderers_rss_private_, u"Renderers",
u"Sum of RSS private memory of\n--type=renderer Chrome process.",
formatter},
{graph_mem_used_unknown_, u"Other",
u"Amount of other used memory.\nEquals to total used minus known.",
formatter},
{graph_mem_free_, u"Free", u"Free memory as reported by kernel.",
formatter},
{graph_chrome_rss_private_, u"Browser",
u"RSS private memory of the\nmain Chrome process.", formatter}
});
CreateLegend(legend);
}
MemoryGraphPageView::~MemoryGraphPageView() = default;
void MemoryGraphPageView::OnPaint(gfx::Canvas* canvas) {
gfx::Rect rect = GetContentsBounds();
rect.Inset(kHUDGraphReferenceLineWidth);
graph_chrome_rss_private_.Layout(rect, nullptr);
graph_mem_free_.Layout(rect, &graph_chrome_rss_private_);
graph_mem_used_unknown_.Layout(rect, &graph_mem_free_);
graph_renderers_rss_private_.Layout(rect, &graph_mem_used_unknown_);
graph_arc_rss_private_.Layout(rect, &graph_renderers_rss_private_);
graph_gpu_rss_private_.Layout(rect, &graph_arc_rss_private_);
graph_gpu_kernel_.Layout(rect, &graph_gpu_rss_private_);
graph_chrome_rss_shared_.Layout(rect, nullptr);
graph_chrome_rss_private_.Draw(canvas);
graph_mem_free_.Draw(canvas);
graph_mem_used_unknown_.Draw(canvas);
graph_renderers_rss_private_.Draw(canvas);
graph_arc_rss_private_.Draw(canvas);
graph_gpu_rss_private_.Draw(canvas);
graph_gpu_kernel_.Draw(canvas);
graph_chrome_rss_shared_.Draw(canvas);
}
void MemoryGraphPageView::UpdateData(const DataSource::Snapshot& snapshot) {
const double total = snapshot.total_ram;
if (total < 1)
return;
constexpr float one_gigabyte = 1024 * 1024 * 1024;
if (total_ram_ != total) {
total_ram_ = total;
reference_lines_->SetTopLabel(total / one_gigabyte);
reference_lines_->SetVisible(true);
}
const float chrome_rss_private_unscaled =
(snapshot.browser_rss - snapshot.browser_rss_shared);
const float chrome_rss_private = chrome_rss_private_unscaled / total;
const float mem_free_unscaled = snapshot.free_ram;
const float mem_free = mem_free_unscaled / total;
const float renderers_rss_private_unscaled =
snapshot.renderers_rss - snapshot.renderers_rss_shared;
const float renderers_rss_private = renderers_rss_private_unscaled / total;
const float arc_rss_private_unscaled =
snapshot.arc_rss - snapshot.arc_rss_shared;
const float arc_rss_private = arc_rss_private_unscaled / total;
const float gpu_rss_private_unscaled =
snapshot.gpu_rss - snapshot.gpu_rss_shared;
const float gpu_rss_private = gpu_rss_private_unscaled / total;
const float gpu_kernel_unscaled = snapshot.gpu_kernel;
const float gpu_kernel = gpu_kernel_unscaled / total;
const float chrome_rss_shared_unscaled = snapshot.browser_rss_shared;
const float chrome_rss_shared = chrome_rss_shared_unscaled / total;
std::vector<float> used_buckets;
used_buckets.push_back(chrome_rss_private);
used_buckets.push_back(mem_free);
used_buckets.push_back(renderers_rss_private);
used_buckets.push_back(arc_rss_private);
used_buckets.push_back(gpu_rss_private);
used_buckets.push_back(gpu_kernel);
const float mem_used_unknown =
1 - std::accumulate(used_buckets.begin(), used_buckets.end(), 0.0f);
const float mem_used_unknown_unscaled = mem_used_unknown * total;
if (mem_used_unknown < 0)
LOG(WARNING) << "mem_used_unknown=" << mem_used_unknown << " < 0 !";
graph_chrome_rss_private_.AddValue(
chrome_rss_private, chrome_rss_private_unscaled / one_gigabyte);
graph_mem_free_.AddValue(mem_free, mem_free_unscaled / one_gigabyte);
graph_mem_used_unknown_.AddValue(
std::max(mem_used_unknown, 0.0f),
std::max(mem_used_unknown_unscaled / one_gigabyte, 0.0f));
graph_renderers_rss_private_.AddValue(
renderers_rss_private, renderers_rss_private_unscaled / one_gigabyte);
graph_arc_rss_private_.AddValue(arc_rss_private,
arc_rss_private_unscaled / one_gigabyte);
graph_gpu_rss_private_.AddValue(gpu_rss_private,
gpu_rss_private_unscaled / one_gigabyte);
graph_gpu_kernel_.AddValue(gpu_kernel, gpu_kernel_unscaled / one_gigabyte);
graph_chrome_rss_shared_.AddValue(chrome_rss_shared,
chrome_rss_shared_unscaled / one_gigabyte);
RefreshLegendValues();
}
}
}