1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
// Copyright 2018 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_BROWSER_METRICS_PERF_PERF_EVENTS_COLLECTOR_H_
#define CHROME_BROWSER_METRICS_PERF_PERF_EVENTS_COLLECTOR_H_
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "base/time/time.h"
#include "chrome/browser/metrics/perf/metric_collector.h"
#include "chrome/browser/metrics/perf/perf_output.h"
#include "chrome/browser/metrics/perf/random_selector.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
#include "third_party/metrics_proto/system_profile.pb.h"
namespace ash {
class DebugDaemonClientProvider;
}
namespace base {
class SequencedTaskRunner;
}
namespace metrics {
struct CPUIdentity;
class WindowedIncognitoObserver;
// Enables collection of perf events profile data. perf aka "perf events" is a
// performance profiling infrastructure built into the linux kernel. For more
// information, see: https://perf.wiki.kernel.org/index.php/Main_Page.
class PerfCollector : public internal::MetricCollector {
public:
PerfCollector();
PerfCollector(const PerfCollector&) = delete;
PerfCollector& operator=(const PerfCollector&) = delete;
// MetricCollector:
~PerfCollector() override;
const char* ToolName() const override;
protected:
// For testing to mock PerfOutputCall.
virtual std::unique_ptr<PerfOutputCall> CreatePerfOutputCall(
const std::vector<std::string>& quipper_args,
bool disable_cpu_idle,
PerfOutputCall::DoneCallback callback);
void OnPerfOutputComplete(
std::unique_ptr<WindowedIncognitoObserver> incognito_observer,
std::unique_ptr<SampledProfile> sampled_profile,
bool has_cycles,
std::string perf_stdout);
// Parses a PerfDataProto from serialized data |perf_stdout|, if non-empty.
// If |perf_stdout| is empty, it is counted as an error. |incognito_observer|
// indicates whether an incognito window had been opened during the profile
// collection period. If there was an incognito window, discard the incoming
// data.
void ParseOutputProtoIfValid(
std::unique_ptr<WindowedIncognitoObserver> incognito_observer,
std::unique_ptr<SampledProfile> sampled_profile,
bool has_cycles,
std::string perf_stdout);
// MetricCollector:
void SetUp() override;
base::WeakPtr<internal::MetricCollector> GetWeakPtr() override;
bool ShouldCollect() const override;
void CollectProfile(std::unique_ptr<SampledProfile> sampled_profile) override;
void StopCollection() override;
const RandomSelector& command_selector() const { return command_selector_; }
// Collects both Ash and Lacros Chrome process and thread types.
static void CollectProcessTypes(SampledProfile* sampled_profile);
// Executes asynchronously on another thread pool and retries with a delay if
// all frequencies couldn't be read. Posts a task on the given task_runner
// after each attempt.
static void ParseCPUFrequencies(
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::WeakPtr<PerfCollector> perf_collector,
int attempt,
int max_retries);
// Saves the given frequencies to |max_frequencies_mhz_|.
void SaveCPUFrequencies(const std::vector<uint32_t>& frequencies);
const std::vector<uint32_t>& max_frequencies_mhz() const {
return max_frequencies_mhz_;
}
// Enumeration representing success and various failure modes for parsing CPU
// frequencies. These values are persisted to logs. Entries should not be
// renumbered and numeric values should never be reused.
enum class ParseFrequencyStatus {
kSuccess,
kNumCPUsIsZero,
kSomeZeroCPUFrequencies,
kAllZeroCPUFrequencies,
kSuccessOnRetry,
kNumCPUsMoreThanPossible,
// Magic constant used by the histogram macros.
kMaxValue = kNumCPUsMoreThanPossible,
};
// Extracts the |lacros_channel| and |lacros_version| from |lacros_path|.
static bool LacrosChannelAndVersion(
std::string_view lacros_path,
metrics::SystemProfileProto_Channel& lacros_channel,
std::string& lacros_version);
// Enumeration of various locations gotten from parsing a Lacros binary path.
// This is used to monitor any change to the Lacros path.
enum class ParseLacrosPath {
kRootfs,
kStateful,
kUnrecognized,
// Magic constant used by the histogram macros.
kMaxValue = kUnrecognized,
};
// Annotations on the collected sampled_profile, including adding process
// types and PSI CPU data.
static void PostCollectionProfileAnnotation(SampledProfile* sampled_profile,
bool has_cycles);
// Collect PSI CPU data and add to sampled_profile.
static void CollectPSICPU(SampledProfile* sampled_profile,
const std::string& psi_cpu_path);
// Enumeration representing success and various failure modes for parsing PSI
// CPU data. These values are persisted to logs. Entries should not be
// renumbered and numeric values should never be reused.
enum class ParsePSICPUStatus {
kSuccess,
kReadFileFailed,
kUnexpectedDataFormat,
kParsePSIValueFailed,
// Magic constant used by the histogram macros.
kMaxValue = kParsePSIValueFailed,
};
SampledProfile::TriggerEvent current_trigger_ =
SampledProfile::UNKNOWN_TRIGGER_EVENT;
// Enumeration representing event types that need additional treatment
// during or after the collection.
enum class EventType {
kOther,
kCycles,
kETM,
};
static EventType CommandEventType(const std::vector<std::string>& args);
private:
// Change the values in |collection_params_| and the commands in
// |command_selector| for any keys that are present in |params|.
void SetCollectionParamsFromVariationParams(
const std::map<std::string, std::string>& params);
// Set of commands to choose from.
RandomSelector command_selector_;
// |debugd_client_provider_| hosts the private DBus connection to debugd.
std::unique_ptr<ash::DebugDaemonClientProvider> debugd_client_provider_;
// An active call to perf/quipper, if set.
std::unique_ptr<PerfOutputCall> perf_output_call_;
// Vector of max frequencies associated with each logical CPU. Computed
// asynchronously at start.
std::vector<uint32_t> max_frequencies_mhz_;
base::WeakPtrFactory<PerfCollector> weak_factory_{this};
};
// Exposed for unit testing.
namespace internal {
// Return the default set of perf commands and their odds of selection given
// the identity of the CPU in |cpuid|.
std::vector<RandomSelector::WeightAndValue> GetDefaultCommandsForCpuModel(
const CPUIdentity& cpuid,
const std::string& model);
// For the "PerfCommand::"-prefixed keys in |params|, return the cpu specifier
// that is the narrowest match for the CPU identified by |cpuid|.
// Valid CPU specifiers, in increasing order of specificity, are:
// "default", a system architecture (e.g. "x86_64"), a CPU microarchitecture
// (currently only some Intel and AMD uarchs supported), or a CPU model name
// substring.
std::string FindBestCpuSpecifierFromParams(
const std::map<std::string, std::string>& params,
const CPUIdentity& cpuid);
// Returns if the given perf command samples CPU cycles.
bool CommandSamplesCPUCycles(const std::vector<std::string>& args);
} // namespace internal
} // namespace metrics
#endif // CHROME_BROWSER_METRICS_PERF_PERF_EVENTS_COLLECTOR_H_
|