chromium/chrome/browser/metrics/process_memory_metrics_emitter.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/browser/metrics/process_memory_metrics_emitter.h"

#include <set>
#include <string>
#include <string_view>
#include <utility>

#include "base/allocator/buildflags.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/page_size.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/process/process_metrics.h"
#include "base/strings/stringprintf.h"
#include "base/task/sequenced_task_runner.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/tab_footprint_aggregator.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_switches.h"
#include "components/metrics/metrics_data_validation.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/graph_operations.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/graph/process_node.h"
#include "components/performance_manager/public/performance_manager.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "content/public/browser/audio_service_info.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
#include "extensions/buildflags/buildflags.h"
#include "media/mojo/mojom/cdm_service.mojom.h"
#include "partition_alloc/buildflags.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/child_process_binding_types.h"
#include "base/android/meminfo_dump_provider.h"
#endif

#if BUILDFLAG(IS_WIN)
#include "media/mojo/mojom/media_foundation_service.mojom.h"
#endif

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/process_map.h"
#include "extensions/common/extension.h"
#endif

MemoryAllocatorDump;
GetPrivateFootprintHistogramName;
GlobalMemoryDump;
HistogramProcessType;
HistogramProcessTypeToString;
kMemoryHistogramPrefix;
Memory_Experimental;

namespace {

const char kEffectiveSize[] =;
const char kSize[] =;
const char kAllocatedObjectsSize[] =;
#if BUILDFLAG(IS_CHROMEOS)
const char kNonExoSize[] = "non_exo_size";
#endif

constexpr int kKiB =;
constexpr int kMiB =;

struct MetricRange {};

const MetricRange ImageSizeMetricRange =;

// Prefer predefined ranges kLarge, kSmall and kTiny over custom ranges.
enum class MetricSize {};

enum class EmitTo {};

struct Metric {};

const Metric kAllocatorDumpNamesForMetrics[] =;

#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// Metrics specific to PartitionAlloc's address space stats (cf.
// kAllocatorDumpNamesForMetrics above). All of these metrics come in
// three variants: bare, after 1 hour, and after 24 hours. These metrics
// are only recorded in UMA.
const Metric kPartitionAllocAddressSpaceMetrics[] =;
#endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)

// Record a memory size in megabytes, over a potential interval up to 32 GB.
#define UMA_HISTOGRAM_LARGE_MEMORY_MB(name, sample)

#define EXPERIMENTAL_UMA_PREFIX
#define VERSION_SUFFIX_PERCENT
#define VERSION_SUFFIX_NORMAL
#define VERSION_SUFFIX_SMALL
#define VERSION_SUFFIX_TINY
#define VERSION_SUFFIX_CUSTOM

void EmitProcessUkm(const Metric& item,
                    uint64_t value,
                    Memory_Experimental* builder) {}

const char* MetricSizeToVersionSuffix(MetricSize size) {}

void EmitProcessUma(HistogramProcessType process_type,
                    const Metric& item,
                    uint64_t value) {}

void EmitPartitionAllocFragmentationStat(
    const GlobalMemoryDump::ProcessDump& pmd,
    HistogramProcessType process_type,
    const char* dump_name,
    const char* uma_name) {}

void EmitPartitionAllocWastedStat(const GlobalMemoryDump::ProcessDump& pmd,
                                  HistogramProcessType process_type,
                                  const char* dump_name,
                                  const char* uma_name) {}

void EmitMallocStats(const GlobalMemoryDump::ProcessDump& pmd,
                     HistogramProcessType process_type,
                     const std::optional<base::TimeDelta>& uptime) {}

#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
void EmitPartitionAllocAddressSpaceStatVariants(
    const Metric& metric,
    const uint64_t metric_value,
    HistogramProcessType process_type,
    const std::optional<base::TimeDelta>& uptime) {}

void EmitPartitionAllocAddressSpaceStats(
    const GlobalMemoryDump::ProcessDump& pmd,
    HistogramProcessType process_type,
    const std::optional<base::TimeDelta>& uptime) {}
#endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)

void EmitProcessUmaAndUkm(const GlobalMemoryDump::ProcessDump& pmd,
                          HistogramProcessType process_type,
                          const std::optional<base::TimeDelta>& uptime,
                          bool record_uma,
                          Memory_Experimental* builder) {}

void EmitSummedGpuMemory(const GlobalMemoryDump::ProcessDump& pmd,
                         Memory_Experimental* builder,
                         bool record_uma) {}

#if BUILDFLAG(IS_CHROMEOS)
void EmitGpuMemoryNonExo(const GlobalMemoryDump::ProcessDump& pmd,
                         bool record_uma) {
  if (!record_uma) {
    return;
  }
  Metric synthetic_metric = {
      nullptr, "GpuMemoryNonExo",      MetricSize::kLarge,
      kSize,   EmitTo::kSizeInUmaOnly, nullptr};

  // Combine several categories together to sum up Chrome-reported gpu memory.
  uint64_t total = 0;
  total += pmd.GetMetric("gpu/shared_images", kNonExoSize).value_or(0);
  total += pmd.GetMetric("skia/gpu_resources", kSize).value_or(0);

  // We only report this metric for the GPU process, so we always use kGpu.
  EmitProcessUma(HistogramProcessType::kGpu, synthetic_metric, total);
}
#endif  // BUILDFLAG(IS_CHROMEOS)

void EmitBrowserMemoryMetrics(const GlobalMemoryDump::ProcessDump& pmd,
                              ukm::SourceId ukm_source_id,
                              ukm::UkmRecorder* ukm_recorder,
                              const std::optional<base::TimeDelta>& uptime,
                              bool record_uma) {}

void EmitRendererMemoryMetrics(
    const GlobalMemoryDump::ProcessDump& pmd,
    const ProcessMemoryMetricsEmitter::PageInfo* page_info,
    ukm::UkmRecorder* ukm_recorder,
    int number_of_extensions,
    const std::optional<base::TimeDelta>& uptime,
    bool record_uma) {}

void EmitGpuMemoryMetrics(const GlobalMemoryDump::ProcessDump& pmd,
                          ukm::SourceId ukm_source_id,
                          ukm::UkmRecorder* ukm_recorder,
                          const std::optional<base::TimeDelta>& uptime,
                          bool record_uma) {}

void EmitUtilityMemoryMetrics(HistogramProcessType ptype,
                              const GlobalMemoryDump::ProcessDump& pmd,
                              ukm::SourceId ukm_source_id,
                              ukm::UkmRecorder* ukm_recorder,
                              const std::optional<base::TimeDelta>& uptime,
                              bool record_uma) {}

#if BUILDFLAG(IS_ANDROID)
// Return the base::android::ChildBindingState if the process with `pid` is a
// renderer. If the `pid` is not in the list of live renderers it is assumed to
// be unbound. If the `process_type` is not for a renderer return nullopt.
std::optional<base::android::ChildBindingState>
GetAndroidRendererProcessBindingState(
    memory_instrumentation::mojom::ProcessType process_type,
    base::ProcessId pid) {
  if (process_type != memory_instrumentation::mojom::ProcessType::RENDERER) {
    return std::nullopt;
  }
  for (auto iter = content::RenderProcessHost::AllHostsIterator();
       !iter.IsAtEnd(); iter.Advance()) {
    if (!iter.GetCurrentValue()->GetProcess().IsValid())
      continue;

    if (iter.GetCurrentValue()->GetProcess().Pid() == pid) {
      return iter.GetCurrentValue()->GetEffectiveChildBindingState();
    }
  }
  // This can occur if the process no longer exists. Specifically, it is
  // possible a memory dump was requested, but the process was killed before
  // reaching this point so we cannot check its status. Treat as UNBOUND.
  return base::android::ChildBindingState::UNBOUND;
}
#endif  // BUILDFLAG(IS_ANDROID)

}  // namespace

ProcessMemoryMetricsEmitter::ProcessMemoryMetricsEmitter()
    :{}

ProcessMemoryMetricsEmitter::ProcessMemoryMetricsEmitter(
    base::ProcessId pid_scope)
    :{}

void ProcessMemoryMetricsEmitter::FetchAndEmitProcessMemoryMetrics() {}

void ProcessMemoryMetricsEmitter::MarkServiceRequestsInProgress() {}

ProcessMemoryMetricsEmitter::~ProcessMemoryMetricsEmitter() {}

void ProcessMemoryMetricsEmitter::ReceivedMemoryDump(
    bool success,
    std::unique_ptr<GlobalMemoryDump> dump) {}

void ProcessMemoryMetricsEmitter::ReceivedProcessInfos(
    std::vector<ProcessInfo> process_infos) {}

ukm::UkmRecorder* ProcessMemoryMetricsEmitter::GetUkmRecorder() {}

int ProcessMemoryMetricsEmitter::GetNumberOfExtensions(base::ProcessId pid) {}

std::optional<base::TimeDelta> ProcessMemoryMetricsEmitter::GetProcessUptime(
    base::TimeTicks now,
    base::ProcessId pid) {}

void ProcessMemoryMetricsEmitter::CollateResults() {}

namespace {

// Returns true iff the given |process| is responsible for hosting the
// main-frame of the given |page|.
bool HostsMainFrame(const performance_manager::ProcessNode* process,
                    const performance_manager::PageNode* page) {}

}  // namespace

void ProcessMemoryMetricsEmitter::GetProcessToPageInfoMap(
    GetProcessToPageInfoMapCallback callback,
    performance_manager::Graph* graph) {}

ProcessMemoryMetricsEmitter::ProcessInfo::ProcessInfo() = default;

ProcessMemoryMetricsEmitter::ProcessInfo::ProcessInfo(ProcessInfo&& other) =
    default;

ProcessMemoryMetricsEmitter::ProcessInfo::~ProcessInfo() = default;

ProcessMemoryMetricsEmitter::ProcessInfo&
ProcessMemoryMetricsEmitter::ProcessInfo::operator=(const ProcessInfo& other) =
    default;