Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cobalt/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ source_set("browser") {
"//components/os_crypt/sync",
"//components/prefs",
"//components/variations/service:service",
"//services/resource_coordinator/public/cpp/memory_instrumentation",
"//starboard:starboard_group",
]

Expand Down
44 changes: 44 additions & 0 deletions cobalt/browser/cobalt_browser_main_parts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
#include <memory>

#include "base/path_service.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cobalt/browser/global_features.h"
#include "cobalt/browser/metrics/cobalt_metrics_service_client.h"
#include "cobalt/shell/common/shell_paths.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_coordinator_service.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"

#if BUILDFLAG(IS_ANDROIDTV)
#include "base/android/memory_pressure_listener_android.h"
Expand All @@ -38,8 +42,48 @@

namespace cobalt {

namespace {

void InitializeBrowserMemoryInstrumentationClient() {
if (memory_instrumentation::MemoryInstrumentation::GetInstance()) {
return;
}

auto task_runner = base::trace_event::MemoryDumpManager::GetInstance()
->GetDumpThreadTaskRunner();
if (!task_runner->RunsTasksInCurrentSequence()) {
task_runner->PostTask(
FROM_HERE,
base::BindOnce(&InitializeBrowserMemoryInstrumentationClient));
return;
}

if (memory_instrumentation::MemoryInstrumentation::GetInstance()) {
return;
}

// Register the browser process as a memory-instrumentation client.
// This replicates content::InitializeBrowserMemoryInstrumentationClient()
// while avoiding unauthorized header includes.
mojo::PendingRemote<memory_instrumentation::mojom::Coordinator> coordinator;
mojo::PendingRemote<memory_instrumentation::mojom::ClientProcess> process;
auto process_receiver = process.InitWithNewPipeAndPassReceiver();
content::GetMemoryInstrumentationRegistry()->RegisterClientProcess(
coordinator.InitWithNewPipeAndPassReceiver(), std::move(process),
memory_instrumentation::mojom::ProcessType::BROWSER,
base::GetCurrentProcId(), /*service_name=*/std::nullopt);
memory_instrumentation::ClientProcessImpl::CreateInstance(
std::move(process_receiver), std::move(coordinator),
/*is_browser_process=*/true);
}

} // namespace

int CobaltBrowserMainParts::PreCreateThreads() {
SetupMetrics();

InitializeBrowserMemoryInstrumentationClient();

#if BUILDFLAG(IS_ANDROIDTV)
base::android::MemoryPressureListenerAndroid::Initialize(
base::android::AttachCurrentThread());
Expand Down
30 changes: 18 additions & 12 deletions cobalt/browser/metrics/cobalt_memory_metrics_emitter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,33 +64,33 @@ const CobaltMemoryMetricsEmitter::Metric kAllocatorDumpNamesForMetrics[] = {
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
{}},
{"blink_objects/Document",
"NumberOfDocuments",
"Tiny.NumberOfDocuments",
CobaltMemoryMetricsEmitter::MetricSize::kTiny,
MemoryAllocatorDump::kNameObjectCount,
CobaltMemoryMetricsEmitter::EmitTo::kCountsInUkmAndSizeInUma,
{}},
{"blink_objects/Frame",
"NumberOfFrames",
"Tiny.NumberOfFrames",
CobaltMemoryMetricsEmitter::MetricSize::kTiny,
MemoryAllocatorDump::kNameObjectCount,
CobaltMemoryMetricsEmitter::EmitTo::kCountsInUkmAndSizeInUma,
{}},
{"blink_objects/LayoutObject",
"NumberOfLayoutObjects",
"Tiny.NumberOfLayoutObjects",
CobaltMemoryMetricsEmitter::MetricSize::kTiny,
MemoryAllocatorDump::kNameObjectCount,
CobaltMemoryMetricsEmitter::EmitTo::kCountsInUkmAndSizeInUma,
{}},
{"blink_objects/Node",
"NumberOfNodes",
"Small.NumberOfNodes",
CobaltMemoryMetricsEmitter::MetricSize::kSmall,
MemoryAllocatorDump::kNameObjectCount,
CobaltMemoryMetricsEmitter::EmitTo::kCountsInUkmAndSizeInUma,
{}},
{"font_caches",
"FontCaches",
{"font_caches/shape_caches",
"Small.FontCaches",
CobaltMemoryMetricsEmitter::MetricSize::kSmall,
kEffectiveSize,
"size",
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
{}},
{"java_heap",
Expand All @@ -100,7 +100,7 @@ const CobaltMemoryMetricsEmitter::Metric kAllocatorDumpNamesForMetrics[] = {
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
{}},
{"leveldatabase",
"LevelDatabase",
"Small.LevelDatabase",
CobaltMemoryMetricsEmitter::MetricSize::kSmall,
kEffectiveSize,
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
Expand Down Expand Up @@ -135,14 +135,20 @@ const CobaltMemoryMetricsEmitter::Metric kAllocatorDumpNamesForMetrics[] = {
kEffectiveSize,
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
{}},
{"skia/sk_glyph_cache",
"Skia.Small.SkGlyphCache",
CobaltMemoryMetricsEmitter::MetricSize::kSmall,
"size",
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
{}},
{"sqlite",
"Sqlite",
"Small.Sqlite",
CobaltMemoryMetricsEmitter::MetricSize::kSmall,
kEffectiveSize,
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
{}},
{"ui",
"UI",
"Small.UI",
CobaltMemoryMetricsEmitter::MetricSize::kSmall,
kEffectiveSize,
CobaltMemoryMetricsEmitter::EmitTo::kSizeInUkmAndUma,
Expand Down Expand Up @@ -171,8 +177,8 @@ const CobaltMemoryMetricsEmitter::Metric kAllocatorDumpNamesForMetrics[] = {

constexpr char kExperimentalUmaPrefix[] = "Memory.Experimental.";
constexpr char kVersionSuffixNormal[] = "2.";
constexpr char kVersionSuffixSmall[] = "2.Small.";
constexpr char kVersionSuffixTiny[] = "2.Tiny.";
constexpr char kVersionSuffixSmall[] = "2.";
constexpr char kVersionSuffixTiny[] = "2.";

static const char* MetricSizeToVersionSuffix(
CobaltMemoryMetricsEmitter::MetricSize size) {
Expand Down
1 change: 1 addition & 0 deletions cobalt/browser/metrics/cobalt_metrics_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ IN_PROC_BROWSER_TEST_F(CobaltMetricsBrowserTest, RecordsMemoryMetrics) {
check_histogram("Memory.Experimental.Browser2.V8");
check_histogram("Memory.Experimental.Browser2.V8.AllocatedObjects");
check_histogram("Memory.Experimental.Browser2.Skia");
check_histogram("Memory.Experimental.Browser2.Skia.Small.SkGlyphCache");
check_histogram("Memory.Experimental.Browser2.Small.FontCaches");
check_histogram("Memory.Experimental.Browser2.Small.LevelDatabase");
check_histogram("Memory.Experimental.Browser2.Small.UI");
Expand Down
18 changes: 18 additions & 0 deletions cobalt/browser/metrics/cobalt_metrics_service_client_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ class TestProcessMemoryMetricsEmitter : public CobaltMemoryMetricsEmitter {
malloc_dump->numeric_entries["allocated_objects_size"] = 8 * 1024 * 1024;
browser_dump->chrome_allocator_dumps["malloc"] = std::move(malloc_dump);

// Add Skia Glyph Cache dump
auto skia_dump = memory_instrumentation::mojom::AllocatorMemDump::New();
skia_dump->numeric_entries["size"] = 2 * 1024 * 1024;
browser_dump->chrome_allocator_dumps["skia/sk_glyph_cache"] =
std::move(skia_dump);

// Add Font Caches dump
auto font_dump = memory_instrumentation::mojom::AllocatorMemDump::New();
font_dump->numeric_entries["size"] = 512 * 1024;
browser_dump->chrome_allocator_dumps["font_caches/shape_caches"] =
std::move(font_dump);

dump_ptr->process_dumps.push_back(std::move(browser_dump));

auto global_dump =
Expand Down Expand Up @@ -368,6 +380,12 @@ TEST_F(CobaltMetricsServiceClientTest, RecordMemoryMetricsRecordsHistogram) {
.GetAllSamples("Memory.Experimental.Browser2.Malloc.AllocatedObjects")
.size(),
1u);

// Experimental histograms (now with .Small. suffix in KB)
histogram_tester.ExpectUniqueSample(
"Memory.Experimental.Browser2.Skia.Small.SkGlyphCache", 2048, 1);
histogram_tester.ExpectUniqueSample(
"Memory.Experimental.Browser2.Small.FontCaches", 512, 1);
}

TEST_F(CobaltMetricsServiceClientTest,
Expand Down
100 changes: 100 additions & 0 deletions cobalt/browser/metrics/font_metrics_browsertest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2026 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/threading/thread_restrictions.h"
#include "cobalt/browser/global_features.h"
#include "cobalt/browser/metrics/cobalt_metrics_service_client.h"
#include "cobalt/browser/metrics/cobalt_metrics_services_manager_client.h"
#include "cobalt/browser/switches.h"
#include "cobalt/testing/browser_tests/browser/test_shell.h"
#include "cobalt/testing/browser_tests/content_browser_test.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cobalt {

class FontMetricsBrowserTest : public content::ContentBrowserTest {
public:
FontMetricsBrowserTest() = default;
~FontMetricsBrowserTest() override = default;

void SetUpCommandLine(base::CommandLine* command_line) override {
content::ContentBrowserTest::SetUpCommandLine(command_line);
// Set a short interval for memory metrics to verify periodic recording.
command_line->AppendSwitchASCII(switches::kMemoryMetricsInterval, "1");
}
};

IN_PROC_BROWSER_TEST_F(FontMetricsBrowserTest, RecordsFontHistograms) {
base::HistogramTester histogram_tester;

base::ScopedAllowBlockingForTesting allow_blocking;
auto* features = GlobalFeatures::GetInstance();

// Ensure metrics recording is started.
features->metrics_services_manager()->UpdateUploadPermissions(true);

// Load a page with various characters to exercise font caches and fallback in
// Blink.
std::string html_content = R"(
<html>
<body>
<p>Standard Latin text.</p>
<p>Emoji: 😀 😃 😄 😁 😆 😅 😂 🤣 🦩 🦒 🦚 🦝</p>
<p>Rare CJK: 𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕</p>
</body>
</html>
)";

GURL url("data:text/html;charset=utf-8," + html_content);
ASSERT_TRUE(content::NavigateToURL(shell()->web_contents(), url));

// Trigger a memory dump manually for testing.
auto* manager_client = features->metrics_services_manager_client();
ASSERT_TRUE(manager_client);
auto* client = static_cast<CobaltMetricsServiceClient*>(
manager_client->metrics_service_client());
ASSERT_TRUE(client);

base::RunLoop run_loop;
client->ScheduleRecordForTesting(run_loop.QuitClosure());
run_loop.Run();

base::RunLoop().RunUntilIdle();

// Check for memory histograms (Skia Glyph Cache).
EXPECT_GE(
histogram_tester.GetAllSamples("Memory.Browser.PrivateMemoryFootprint")
.size(),
1u);

EXPECT_GE(
histogram_tester
.GetAllSamples("Memory.Experimental.Browser2.Skia.Small.SkGlyphCache")
.size(),
1u);

EXPECT_GE(histogram_tester
.GetAllSamples("Memory.Experimental.Browser2.Small.FontCaches")
.size(),
1u);
}

} // namespace cobalt
60 changes: 60 additions & 0 deletions cobalt/docs/font_metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Font Resource and Memory Usage Metrics in Cobalt

This document summarizes the UMA histograms, Memory Infra dumps, and performance metrics used to track font, glyph cache, and text rendering resource usage in Cobalt.

## 1. Memory Consumption (Memory Infra / UMA)

These metrics track actual bytes used in RAM and GPU memory.

### Skia Graphics Layer
* **Skia Glyph Cache**
* **Dump Path**: `skia/sk_glyph_cache`
* **UMA Mapping**: `Memory.Experimental.[Process].Skia.SkGlyphCache`
* **Description**: Tracks the memory used by Skia's internal "Strike" cache (rasterized glyph masks).
* **Source**: `skia/ext/skia_memory_dump_provider.cc` via `SkGraphics::GetFontCacheUsed()`.
* **Cobalt Status**: Enabled in `cobalt/tools/uma/memory_histograms.txt`.

* **GPU Glyph Atlas**
* **Dump Path**: `skia/gpu_resources/glyph_atlas` (in Chromium/Skia)
* **UMA Mapping**: `Memory.Gpu.Skia.GpuResources.GlyphAtlas`
* **Description**: Memory used by the GPU texture atlas where glyphs are packed for hardware-accelerated rendering.

### Blink / Renderer Layer
* **Font Shape Caches**
* **Dump Path**: `font_caches/shape_caches`
* **UMA Mapping**: `Memory.Experimental.[Process].FontCaches`
* **Description**: Memory used for caching text shaping results (the output of HarfBuzz).
* **Source**: `third_party/blink/renderer/platform/fonts/font_cache.cc`.

* **Font Platform Data Cache**
* **Dump Path**: `font_caches/font_platform_data_cache`
* **Description**: Tracks memory used by the cache of platform-specific font handles.
* **Allowlist**: Included in `base/trace_event/memory_infra_background_allowlist.cc`.

## 2. Resource Efficiency & Cache Performance

* **RenderTextHarfBuzz.ShapeRunsFallback**
* **Type**: Enumeration
* **Description**: Tracks how often font fallback is triggered during the text shaping phase.
* **Source**: `ui/gfx/render_text_harfbuzz.cc`.

* **RenderTextHarfBuzz.GetFallbackFontTime**
* **Type**: Times (ms)
* **Description**: Time spent searching for a suitable fallback font when a character is missing.
* **Source**: `ui/gfx/render_text_harfbuzz.cc`.

* **Blink.Fonts.DecodeTime**
* **Type**: Microseconds
* **Description**: Time spent decoding font resources.
* **Source**: `third_party/blink/renderer/platform/fonts/font_resource.cc`.

## 3. Cobalt Integration Details

* **Metrics Management**: `cobalt/browser/metrics/cobalt_metrics_service_client.cc` coordinates global memory dumps.
* **Allowlist**: Cobalt-specific histogram reporting is controlled by `cobalt/tools/uma/memory_histograms.txt`.

## How to Verify in Cobalt

1. **Memory Dumps**: Trigger a global memory dump via CDP or the internal metrics service to see the `skia/sk_glyph_cache` and `font_caches/*` breakdown.
2. **UMA Verification**: Use `cobalt/tools/uma/pull_uma_histogram_set_via_cdp.py` to fetch currently recorded histograms from a running Cobalt instance and verify font-related entries.
3. **Unit Tests**: Exercise `ui/gfx/render_text_unittest.cc` or similar tests to see histogram emission in a controlled environment.
1 change: 1 addition & 0 deletions cobalt/testing/browser_tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ test("cobalt_browsertests") {
sources = [
# TODO(b/458665232): restore browser tests in M138.
"//cobalt/browser/metrics/cobalt_metrics_browsertest.cc",
"//cobalt/browser/metrics/font_metrics_browsertest.cc",
"content_main_runner_impl_browsertest.cc",

#"encrypted_media_browsertest.cc",
Expand Down
Loading
Loading