blob: 8d09b48d67004c81f1ae56c0b8ae177a287e12b8 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/heap_profiling/in_process/heap_profiler_parameters.h"
#include "base/check_op.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/sampling_profiler/process_type.h"
namespace heap_profiling {
namespace {
// Platform-specific parameter defaults.
#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// Default on iOS is equal to mean value of process uptime. Android is
// more similar to iOS than to Desktop.
constexpr base::TimeDelta kDefaultCollectionInterval = base::Minutes(30);
#else
// Default on desktop is once per day.
constexpr base::TimeDelta kDefaultCollectionInterval = base::Days(1);
#endif
// Average 10M bytes per sample.
constexpr int kDefaultSamplingRateBytes = 10'000'000;
// The chance that this client will report heap samples through a metrics
// provider if it's on the stable channel.
#if BUILDFLAG(IS_ANDROID)
// With stable-probability 0.01 we get about 4x as many records as before
// https://crrev.com/c/3309878 landed in 98.0.4742.0, even with ARM64
// disabled. This is too high a volume to process.
constexpr double kDefaultStableProbability = 0.0025;
#else
constexpr double kDefaultStableProbability = 0.01;
#endif
// The chance that this client will report heap samples through a metrics
// provider if it's on a non-stable channel.
constexpr double kDefaultNonStableProbability = 0.5;
// The probability of including a child process in each snapshot that's taken,
// as a percentage from 0 to 100. Defaults to 100, but can be set lower to
// sub-sample process types that are very common (mainly renderers) to keep data
// volume low. Samples from child processes are weighted in inverse proportion
// to the snapshot probability to normalize the aggregated results. Set to 0 to
// disable sampling a process completely.
constexpr base::FeatureParam<int> kGpuSnapshotProbability{
&kHeapProfilerReporting, "gpu-prob-pct", 100};
constexpr base::FeatureParam<int> kNetworkSnapshotProbability{
&kHeapProfilerReporting, "network-prob-pct", 100};
// Sample 10% of renderer processes by default, because last time this was
// evaluated (2024-08) the 50th %ile of renderer process count
// (Memory.RenderProcessHost.Count2.All) ranged from 8 on Windows to 18 on Mac.
// 10% is an easy default between 1/18 and 1/8.
constexpr base::FeatureParam<int> kRendererSnapshotProbability{
&kHeapProfilerReporting, "renderer-prob-pct",
#if BUILDFLAG(IS_CHROMEOS)
// base::debug::TraceStackFramePointers is crashing in ChromeOS rendererer
// processes. Disable heap profiling there for now.
// TODO(crbug.com/402542102): Find the root cause and re-enable.
0
#else
10
#endif
};
// Sample 50% of utility processes by default, because last time this was
// evaluated (2024-08) the profiler collected 1.8x as many snapshots on Mac and
// 2.4x as many snapshots on Windows for each browser process snapshot.
constexpr base::FeatureParam<int> kUtilitySnapshotProbability{
&kHeapProfilerReporting, "utility-prob-pct", 50};
// The sampling rates of each process type, in bytes.
constexpr base::FeatureParam<int> kBrowserSamplingRateBytes{
&kHeapProfilerReporting, "browser-sampling-rate-bytes",
kDefaultSamplingRateBytes};
// Use half the threshold used in the browser process, because last time it was
// validated the GPU process allocated a bit over half as much memory at the
// median.
constexpr base::FeatureParam<int> kGpuSamplingRateBytes{
&kHeapProfilerReporting, "gpu-sampling-rate-bytes",
kDefaultSamplingRateBytes / 2};
constexpr base::FeatureParam<int> kNetworkSamplingRateBytes{
&kHeapProfilerReporting, "network-sampling-rate-bytes",
kDefaultSamplingRateBytes};
constexpr base::FeatureParam<int> kRendererSamplingRateBytes{
&kHeapProfilerReporting, "renderer-sampling-rate-bytes",
kDefaultSamplingRateBytes};
// Use 1/10th the threshold used in the browser process, because last time it
// was validated with the default sampling rate (2024-08) the sampler collected
// 6% to 11% as many samples per snapshot in the utility process, depending on
// platform.
constexpr base::FeatureParam<int> kUtilitySamplingRateBytes{
&kHeapProfilerReporting, "utility-sampling-rate-bytes",
kDefaultSamplingRateBytes / 10};
// The load factor that should be used by PoissonAllocationSampler's hash set in
// each process type.
constexpr base::FeatureParam<double> kBrowserHashSetLoadFactor{
&kHeapProfilerReporting, "browser-hash-set-load-factor", 1.0};
constexpr base::FeatureParam<double> kGpuHashSetLoadFactor{
&kHeapProfilerReporting, "gpu-hash-set-load-factor", 1.0};
constexpr base::FeatureParam<double> kNetworkHashSetLoadFactor{
&kHeapProfilerReporting, "network-hash-set-load-factor", 1.0};
constexpr base::FeatureParam<double> kRendererHashSetLoadFactor{
&kHeapProfilerReporting, "renderer-hash-set-load-factor", 1.0};
constexpr base::FeatureParam<double> kUtilityHashSetLoadFactor{
&kHeapProfilerReporting, "utility-hash-set-load-factor", 1.0};
} // namespace
BASE_FEATURE(kHeapProfilerReporting,
"HeapProfilerReporting",
base::FEATURE_ENABLED_BY_DEFAULT);
const base::FeatureParam<double> kStableProbability{
&kHeapProfilerReporting, "stable-probability", kDefaultStableProbability};
const base::FeatureParam<double> kNonStableProbability{
&kHeapProfilerReporting, "nonstable-probability",
kDefaultNonStableProbability};
const base::FeatureParam<base::TimeDelta> kCollectionInterval{
&kHeapProfilerReporting, "collection-interval", kDefaultCollectionInterval};
size_t GetSamplingRateForProcess(
sampling_profiler::ProfilerProcessType process_type) {
int sampling_rate_bytes;
switch (process_type) {
case sampling_profiler::ProfilerProcessType::kBrowser:
sampling_rate_bytes = kBrowserSamplingRateBytes.Get();
break;
case sampling_profiler::ProfilerProcessType::kRenderer:
sampling_rate_bytes = kRendererSamplingRateBytes.Get();
break;
case sampling_profiler::ProfilerProcessType::kGpu:
sampling_rate_bytes = kGpuSamplingRateBytes.Get();
break;
case sampling_profiler::ProfilerProcessType::kUtility:
sampling_rate_bytes = kUtilitySamplingRateBytes.Get();
break;
case sampling_profiler::ProfilerProcessType::kNetworkService:
sampling_rate_bytes = kNetworkSamplingRateBytes.Get();
break;
case sampling_profiler::ProfilerProcessType::kUnknown:
default:
// Profiler should not be enabled for these process types.
NOTREACHED();
}
return base::saturated_cast<size_t>(sampling_rate_bytes);
}
int GetSnapshotProbabilityForProcess(
sampling_profiler::ProfilerProcessType process_type) {
int snapshot_probability_pct;
switch (process_type) {
case sampling_profiler::ProfilerProcessType::kBrowser:
// Should only be called for child processes.
NOTREACHED();
case sampling_profiler::ProfilerProcessType::kGpu:
snapshot_probability_pct = kGpuSnapshotProbability.Get();
break;
case sampling_profiler::ProfilerProcessType::kNetworkService:
snapshot_probability_pct = kNetworkSnapshotProbability.Get();
break;
case sampling_profiler::ProfilerProcessType::kRenderer:
snapshot_probability_pct = kRendererSnapshotProbability.Get();
break;
case sampling_profiler::ProfilerProcessType::kUtility:
snapshot_probability_pct = kUtilitySnapshotProbability.Get();
break;
default:
// Unsupported process type.
snapshot_probability_pct = 0;
break;
}
CHECK_GE(snapshot_probability_pct, 0);
CHECK_LE(snapshot_probability_pct, 100);
return snapshot_probability_pct;
}
float GetHashSetLoadFactorForProcess(
sampling_profiler::ProfilerProcessType process_type) {
switch (process_type) {
case sampling_profiler::ProfilerProcessType::kBrowser:
return kBrowserHashSetLoadFactor.Get();
case sampling_profiler::ProfilerProcessType::kGpu:
return kGpuHashSetLoadFactor.Get();
case sampling_profiler::ProfilerProcessType::kNetworkService:
return kNetworkHashSetLoadFactor.Get();
case sampling_profiler::ProfilerProcessType::kRenderer:
return kRendererHashSetLoadFactor.Get();
case sampling_profiler::ProfilerProcessType::kUtility:
return kUtilityHashSetLoadFactor.Get();
default:
NOTREACHED();
}
}
} // namespace heap_profiling