blob: 860f1263e117deb3a50dd312cf0568266476a0ce [file] [log] [blame]
// Copyright 2018 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.
#ifndef COMPONENTS_HEAP_PROFILING_IN_PROCESS_HEAP_PROFILER_CONTROLLER_H_
#define COMPONENTS_HEAP_PROFILING_IN_PROCESS_HEAP_PROFILER_CONTROLLER_H_
#include <map>
#include <vector>
#include "base/feature_list.h"
#include "base/memory/ref_counted.h"
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
#include "base/sequence_checker.h"
#include "base/synchronization/atomic_flag.h"
#include "base/time/time.h"
#include "components/metrics/call_stack_profile_params.h"
#include "components/version_info/channel.h"
// HeapProfilerController controls collection of sampled heap allocation
// snapshots for the current process.
class HeapProfilerController {
public:
enum class ProfilingEnabled {
kNoController,
kDisabled,
kEnabled,
};
// Returns kEnabled if heap profiling is enabled, kDisabled if not. If no
// HeapProfilerController exists the profiling state is indeterminate so the
// function returns kNoController.
static ProfilingEnabled GetProfilingEnabled();
// Checks if heap profiling should be enabled for this process. If so, starts
// sampling heap allocations immediately but does not schedule snapshots of
// the samples until Start() is called. `channel` is used to determine the
// probability that this client will be opted in to profiling. `process_type`
// is the current process, which can be retrieved with GetProfileParamsProcess
// in chrome/common/profiler/process_type.h.
explicit HeapProfilerController(
version_info::Channel channel,
metrics::CallStackProfileParams::Process process_type);
HeapProfilerController(const HeapProfilerController&) = delete;
HeapProfilerController& operator=(const HeapProfilerController&) = delete;
~HeapProfilerController();
// Starts periodic heap snapshot collection. Does nothing except record a
// metric if heap profiling is disabled.
void StartIfEnabled();
// Public for testing.
using Sample = base::SamplingHeapProfiler::Sample;
struct SampleComparator {
bool operator()(const Sample& lhs, const Sample& rhs) const;
};
struct SampleValue {
// Sum of all allocations attributed to this Sample's stack trace.
size_t total = 0;
// Count of all allocations attributed to this Sample's stack trace.
size_t count = 0;
};
// The value of the map tracks total size and count of all Samples associated
// with the key's stack trace.
// We use a std::map here since most comparisons will early out in one of the
// first entries in the vector. For reference: the first entry is likely the
// address of the code calling malloc(). Using a hash-based container would
// typically entail hashing the entire contents of the stack trace.
using SampleMap = std::map<Sample, SampleValue, SampleComparator>;
// Merges samples that have identical stack traces, excluding total and size.
static SampleMap MergeSamples(const std::vector<Sample>& samples);
// If this is disabled, the client will not collect heap profiles. If it is
// enabled, the client may enable the sampling heap profiler (with probability
// based on the "stable-probability" parameter if the client is on the stable
// channel, or the "nonstable-probability" parameter otherwise). Sampled heap
// profiles will then be reported through the metrics service iff metrics
// reporting is enabled.
static const base::Feature kHeapProfilerReporting;
// Uses the exact parameter values for the sampling interval and time between
// samples, instead of a distribution around those values. This must be called
// before Start.
void SuppressRandomnessForTesting();
private:
using ProcessType = metrics::CallStackProfileParams::Process;
using StoppedFlag = base::RefCountedData<base::AtomicFlag>;
// Parameters to control the snapshot sampling and reporting. This is
// move-only so that it can be safely passed between threads to the static
// snapshot functions.
struct SnapshotParams {
SnapshotParams(base::TimeDelta mean_interval,
bool use_random_interval,
scoped_refptr<StoppedFlag> stopped,
ProcessType process_type);
~SnapshotParams();
// Move-only.
SnapshotParams(const SnapshotParams& other) = delete;
SnapshotParams& operator=(const SnapshotParams& other) = delete;
SnapshotParams(SnapshotParams&& other);
SnapshotParams& operator=(SnapshotParams&& other);
// Mean interval until the next snapshot.
base::TimeDelta mean_interval;
// If true, generate a random time centered around `mean_interval`.
// Otherwise use `mean_interval` exactly.
bool use_random_interval = false;
// Atomic flag to signal that no more snapshots should be taken.
scoped_refptr<StoppedFlag> stopped;
// Process being sampled.
ProcessType process_type = ProcessType::kUnknown;
};
static void ScheduleNextSnapshot(SnapshotParams params);
// Takes a heap snapshot unless the `params.stopped` flag is set.
// `previous_interval` is the time since the previous snapshot, which is used
// to log metrics about snapshot frequency.
static void TakeSnapshot(SnapshotParams params,
base::TimeDelta previous_interval);
static void RetrieveAndSendSnapshot(ProcessType process_type);
const ProcessType process_type_;
// This flag is set when the HeapProfilerController is torn down, to stop
// profiling. It is the only member that should be referenced by the static
// functions, to be sure that they can run on the thread pool while
// HeapProfilerController is deleted on the main thread.
scoped_refptr<StoppedFlag> stopped_;
bool suppress_randomness_for_testing_ = false;
SEQUENCE_CHECKER(sequence_checker_);
};
#endif // COMPONENTS_HEAP_PROFILING_IN_PROCESS_HEAP_PROFILER_CONTROLLER_H_