| // 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 "ash/hud_display/memory_graph_page_view.h" |
| |
| #include <algorithm> |
| #include <numeric> |
| |
| #include "ash/hud_display/grid.h" |
| #include "ash/hud_display/hud_constants.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/views/metadata/metadata_impl_macros.h" |
| |
| namespace ash { |
| namespace hud_display { |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // MemoryGraphPageView, public: |
| |
| BEGIN_METADATA(MemoryGraphPageView, GraphPageViewBase) |
| END_METADATA |
| |
| MemoryGraphPageView::MemoryGraphPageView(const base::TimeDelta refresh_interval) |
| : graph_chrome_rss_private_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::SOLID, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorRED, kHUDAlpha)), |
| graph_mem_free_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::NONE, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorDKGRAY, kHUDAlpha)), |
| graph_mem_used_unknown_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::SOLID, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorLTGRAY, kHUDAlpha)), |
| graph_renderers_rss_private_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::SOLID, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorCYAN, kHUDAlpha)), |
| graph_arc_rss_private_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::SOLID, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorMAGENTA, kHUDAlpha)), |
| graph_gpu_rss_private_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::SOLID, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorRED, kHUDAlpha)), |
| graph_gpu_kernel_(kDefaultGraphWidth, |
| Graph::Baseline::BASELINE_BOTTOM, |
| Graph::Fill::SOLID, |
| Graph::Style::LINES, |
| SkColorSetA(SK_ColorYELLOW, kHUDAlpha)), |
| graph_chrome_rss_shared_(kDefaultGraphWidth, |
| 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(); |
| // Verical ticks are drawn every 10% (10/100 interval). |
| constexpr float vertical_ticks_interval = 10 / 100.0; |
| // -XX seconds on the left, 0Gb top (will be updated later), 0 seconds on the |
| // right, 0 Gb on the bottom. Seconds and Gigabytes are dimensions. Number of |
| // data points is data_width. horizontal grid ticks are drawn every 10 |
| // seconds. |
| grid_ = CreateGrid( |
| static_cast<int>(/*left=*/-data_width * refresh_interval.InSecondsF()), |
| /*top=*/0, /*right=*/0, /*bottom=*/0, /*x_unit=*/base::ASCIIToUTF16("s"), |
| /*y_unit=*/base::ASCIIToUTF16("Gb"), |
| /*horizontal_points_number=*/data_width, |
| /*horizontal_ticks_interval=*/10 / refresh_interval.InSecondsF(), |
| vertical_ticks_interval); |
| // Hide grid until we know total memory size. |
| grid_->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_, base::ASCIIToUTF16("GPU Driver"), |
| base::ASCIIToUTF16("Kernel GPU buffers as reported\nby " |
| "base::SystemMemoryInfo::gem_size."), |
| formatter}, |
| {graph_gpu_rss_private_, base::ASCIIToUTF16("Chrome GPU"), |
| base::ASCIIToUTF16( |
| "RSS private memory of\n --type=gpu-process Chrome process."), |
| formatter}, |
| // ARC memory is not usually visible (skipped) |
| {graph_renderers_rss_private_, base::ASCIIToUTF16("Renderers"), |
| base::ASCIIToUTF16( |
| "Sum of RSS private memory of\n--type=renderer Chrome process."), |
| formatter}, |
| {graph_mem_used_unknown_, base::ASCIIToUTF16("Other"), |
| base::ASCIIToUTF16( |
| "Amount of other used memory.\nEquals to total used minus known."), |
| formatter}, |
| {graph_mem_free_, base::ASCIIToUTF16("Free"), |
| base::ASCIIToUTF16("Free memory as reported by kernel."), formatter}, |
| {graph_chrome_rss_private_, base::ASCIIToUTF16("Browser"), |
| base::ASCIIToUTF16("RSS private memory of the\nmain Chrome process."), |
| formatter} |
| // Browser RSS hairline skipped. |
| }); |
| CreateLegend(legend); |
| } |
| |
| MemoryGraphPageView::~MemoryGraphPageView() = default; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void MemoryGraphPageView::OnPaint(gfx::Canvas* canvas) { |
| // TODO: Should probably update last graph point more often than shift graph. |
| |
| // Layout graphs. |
| gfx::Rect rect = GetContentsBounds(); |
| // Adjust to grid width. |
| rect.Inset(kGridLineWidth, kGridLineWidth); |
| graph_chrome_rss_private_.Layout(rect, /*base=*/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_); |
| // Not stacked. |
| graph_chrome_rss_shared_.Layout(rect, /*base=*/nullptr); |
| |
| // Paint damaged area now that all parameters have been determined. |
| 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) { |
| // TODO: Should probably update last graph point more often than shift graph. |
| const double total = snapshot.total_ram; |
| // Nothing to do if data is not available yet. |
| if (total < 1) |
| return; |
| |
| constexpr float one_gigabyte = 1024 * 1024 * 1024; |
| |
| if (total_ram_ != total) { |
| total_ram_ = total; |
| grid_->SetTopLabel(total / one_gigabyte); // In Gigabytes. |
| grid_->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; |
| // mem_used_unknown is calculated below. |
| 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; |
| |
| // not stacked. |
| 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 !"; |
| |
| // Update graph data. |
| 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); |
| // Not stacked. |
| graph_chrome_rss_shared_.AddValue(chrome_rss_shared, |
| chrome_rss_shared_unscaled / one_gigabyte); |
| |
| RefreshLegendValues(); |
| } |
| |
| } // namespace hud_display |
| } // namespace ash |