910e62b5创建于 1月15日历史提交
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_COMMON_PROFILER_THREAD_PROFILER_CONFIGURATION_H_
#define CHROME_COMMON_PROFILER_THREAD_PROFILER_CONFIGURATION_H_

#include <optional>
#include <string>
#include <variant>

#include "base/containers/span.h"
#include "base/no_destructor.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "components/sampling_profiler/process_type.h"

namespace base {
class CommandLine;
}  // namespace base

class ThreadProfilerPlatformConfiguration;

// ThreadProfilerConfiguration chooses a configuration for the enable state of
// the stack sampling profiler across all processes. This configuration is
// determined once at browser process startup. Configurations for child
// processes are communicated via command line arguments.
class ThreadProfilerConfiguration {
 public:
  // Returns the ThreadProfilerConfiguration for the process.
  static ThreadProfilerConfiguration* Get();

  ~ThreadProfilerConfiguration() = delete;
  ThreadProfilerConfiguration(const ThreadProfilerConfiguration&) = delete;
  ThreadProfilerConfiguration& operator=(const ThreadProfilerConfiguration&) =
      delete;

  // Get the stack sampling params to use.
  base::StackSamplingProfiler::SamplingParams GetSamplingParams() const;

  // True if the profiler is enabled for any thread in the current process.
  bool IsProfilerEnabledForCurrentProcess() const;

  // True if the profiler should be started for |thread| in the current process.
  bool IsProfilerEnabledForCurrentProcessAndThread(
      sampling_profiler::ProfilerThreadType thread) const;

  // Get the synthetic field trial configuration. Returns true if a synthetic
  // field trial should be registered. This should only be called from the
  // browser process. When run at startup, the profiler must use a synthetic
  // field trial since it runs before the metrics field trials are initialized.
  bool GetSyntheticFieldTrial(std::string* trial_name,
                              std::string* group_name) const;

  // True if profiler should be enabled for the child process.
  bool IsProfilerEnabledForChildProcess(
      sampling_profiler::ProfilerProcessType child_process) const;

  // Add a command line switch that instructs the child process to run the
  // profiler. This should only be called from the browser process.
  void AppendCommandLineSwitchForChildProcess(
      base::CommandLine* command_line) const;

  // The variation groups that represent the Chrome-wide profiling
  // configurations. Exposed for testing.
  enum VariationGroup {
    // Disabled within the experiment.
    kProfileDisabled,

    // Disabled because the required module is not installed, and outside the
    // experiment.
    kProfileDisabledModuleNotInstalled,

    // Enabled within the experiment (and paired with equal-sized
    // kProfileDisabled group).
    kProfileControl,

    // Enabled outside of the experiment.
    kProfileEnabled,

    // Disabled outside of the experiment.
    kProfileDisabledOutsideOfExperiment,
  };

  // Configuration variations, along with weights to use when randomly choosing
  // one of a set of variations. Exposed for testing.
  struct Variation {
    VariationGroup group;
    double weight;
  };

  // Randomly chooses a variation from the weighted variations. Weights are
  // expected to sum to 100 as a sanity check. Exposed for testing.
  // randValue is a random value in the interval [0, 1) and is used to
  // determine the variation group.
  static VariationGroup ChooseVariationGroup(
      base::span<const Variation> variations,
      double randValue);

 private:
  friend base::NoDestructor<ThreadProfilerConfiguration>;

  struct BrowserProcessConfiguration {
    // The configuration state for the browser process. If !has_value()
    // profiling is disabled and no variations state is reported. Otherwise
    // profiling is enabled based on the VariationGroup and the variation state
    // is reported.
    std::optional<VariationGroup> variation_group;

    // In pick-single-type-of-process-to-sample mode, only a single process
    // type will be profiled when profiling is enabled. If !has_value(), the
    // profiling will be enabled for as many processes as possible.
    std::optional<sampling_profiler::ProfilerProcessType>
        process_type_to_sample;
  };

  // The configuration state in child processes.
  enum ChildProcessConfiguration {
    kChildProcessProfileDisabled,
    kChildProcessProfileEnabled,
  };

  // The configuration state for the current process, browser or child.
  using Configuration =
      std::variant<BrowserProcessConfiguration, ChildProcessConfiguration>;

  ThreadProfilerConfiguration();

  // True if the profiler is to be enabled for |variation_group|.
  static bool EnableForVariationGroup(
      std::optional<VariationGroup> variation_group);

  // True if the given process is picked to enable profiling. In pick-single-
  // type-of-process-to-sample mode, only one type of process is picked to
  // have profiling enabled so that the user impact can be minimized.
  static bool IsProcessGloballyEnabled(
      const ThreadProfilerConfiguration::BrowserProcessConfiguration& config,
      sampling_profiler::ProfilerProcessType process);

  // Generates a configuration for the browser process.
  static BrowserProcessConfiguration GenerateBrowserProcessConfiguration(
      const ThreadProfilerPlatformConfiguration& platform_configuration);

  // Generates a configuration for a child process.
  static ChildProcessConfiguration GenerateChildProcessConfiguration(
      const base::CommandLine& command_line);

  // Generates a configuration for the current process.
  static Configuration GenerateConfiguration(
      sampling_profiler::ProfilerProcessType process,
      const ThreadProfilerPlatformConfiguration& platform_configuration);

  // NOTE: all state in this class must be const and initialized at construction
  // time to ensure thread-safe access post-construction.

  // Platform-dependent configuration upon which |configuration_| is based.
  const std::unique_ptr<ThreadProfilerPlatformConfiguration>
      platform_configuration_;

  // Represents the configuration to use in the current process.
  const Configuration configuration_;
};

#endif  // CHROME_COMMON_PROFILER_THREAD_PROFILER_CONFIGURATION_H_