Clean up extension confirmation prompts and make them consistent between Views and...
[chromium-blink-merge.git] / components / metrics / call_stack_profile_metrics_provider.cc
blob9484776cc8a651b2270b84bd26c24ff3b922ad01
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/metrics/call_stack_profile_metrics_provider.h"
7 #include <cstring>
8 #include <map>
9 #include <utility>
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/profiler/stack_sampling_profiler.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "components/metrics/metrics_hashes.h"
20 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
22 using base::StackSamplingProfiler;
24 namespace metrics {
26 namespace {
28 // Accepts and ignores the completed profiles. Used when metrics reporting is
29 // disabled.
30 void IgnoreCompletedProfiles(
31 const StackSamplingProfiler::CallStackProfiles& profiles) {
34 // The protobuf expects the MD5 checksum prefix of the module name.
35 uint64 HashModuleFilename(const base::FilePath& filename) {
36 const base::FilePath::StringType basename = filename.BaseName().value();
37 // Copy the bytes in basename into a string buffer.
38 size_t basename_length_in_bytes =
39 basename.size() * sizeof(base::FilePath::CharType);
40 std::string name_bytes(basename_length_in_bytes, '\0');
41 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
42 return HashMetricName(name_bytes);
45 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to
46 // compute module instruction pointer offsets.
47 void CopySampleToProto(
48 const StackSamplingProfiler::Sample& sample,
49 const std::vector<StackSamplingProfiler::Module>& modules,
50 CallStackProfile::Sample* proto_sample) {
51 for (const StackSamplingProfiler::Frame& frame : sample) {
52 CallStackProfile::Entry* entry = proto_sample->add_entry();
53 // A frame may not have a valid module. If so, we can't compute the
54 // instruction pointer offset, and we don't want to send bare pointers, so
55 // leave call_stack_entry empty.
56 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex)
57 continue;
58 int64 module_offset =
59 reinterpret_cast<const char*>(frame.instruction_pointer) -
60 reinterpret_cast<const char*>(modules[frame.module_index].base_address);
61 DCHECK_GE(module_offset, 0);
62 entry->set_address(static_cast<uint64>(module_offset));
63 entry->set_module_id_index(frame.module_index);
67 // Transcode |profile| into |proto_profile|.
68 void CopyProfileToProto(
69 const StackSamplingProfiler::CallStackProfile& profile,
70 CallStackProfile* proto_profile) {
71 if (profile.samples.empty())
72 return;
74 if (profile.preserve_sample_ordering) {
75 // Collapse only consecutive repeated samples together.
76 CallStackProfile::Sample* current_sample_proto = nullptr;
77 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
78 if (!current_sample_proto || *it != *(it - 1)) {
79 current_sample_proto = proto_profile->add_sample();
80 CopySampleToProto(*it, profile.modules, current_sample_proto);
81 current_sample_proto->set_count(1);
82 } else {
83 current_sample_proto->set_count(current_sample_proto->count() + 1);
86 } else {
87 // Collapse all repeated samples together.
88 std::map<StackSamplingProfiler::Sample, int> sample_index;
89 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
90 auto location = sample_index.find(*it);
91 if (location == sample_index.end()) {
92 CallStackProfile::Sample* sample_proto = proto_profile->add_sample();
93 CopySampleToProto(*it, profile.modules, sample_proto);
94 sample_proto->set_count(1);
95 sample_index.insert(
96 std::make_pair(
97 *it, static_cast<int>(proto_profile->sample().size()) - 1));
98 } else {
99 CallStackProfile::Sample* sample_proto =
100 proto_profile->mutable_sample()->Mutable(location->second);
101 sample_proto->set_count(sample_proto->count() + 1);
106 for (const StackSamplingProfiler::Module& module : profile.modules) {
107 CallStackProfile::ModuleIdentifier* module_id =
108 proto_profile->add_module_id();
109 module_id->set_build_id(module.id);
110 module_id->set_name_md5_prefix(HashModuleFilename(module.filename));
113 proto_profile->set_profile_duration_ms(
114 profile.profile_duration.InMilliseconds());
115 proto_profile->set_sampling_period_ms(
116 profile.sampling_period.InMilliseconds());
119 // Translates CallStackProfileMetricsProvider's trigger to the corresponding
120 // SampledProfile TriggerEvent.
121 SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
122 CallStackProfileMetricsProvider::Trigger trigger) {
123 switch (trigger) {
124 case CallStackProfileMetricsProvider::UNKNOWN:
125 return SampledProfile::UNKNOWN_TRIGGER_EVENT;
126 break;
127 case CallStackProfileMetricsProvider::PROCESS_STARTUP:
128 return SampledProfile::PROCESS_STARTUP;
129 break;
130 case CallStackProfileMetricsProvider::JANKY_TASK:
131 return SampledProfile::JANKY_TASK;
132 break;
133 case CallStackProfileMetricsProvider::THREAD_HUNG:
134 return SampledProfile::THREAD_HUNG;
135 break;
137 NOTREACHED();
138 return SampledProfile::UNKNOWN_TRIGGER_EVENT;
141 } // namespace
143 const char CallStackProfileMetricsProvider::kFieldTrialName[] =
144 "StackProfiling";
145 const char CallStackProfileMetricsProvider::kReportProfilesGroupName[] =
146 "Report profiles";
148 CallStackProfileMetricsProvider::CallStackProfileMetricsProvider()
149 : weak_factory_(this) {
152 CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {
153 StackSamplingProfiler::SetDefaultCompletedCallback(
154 StackSamplingProfiler::CompletedCallback());
157 void CallStackProfileMetricsProvider::OnRecordingEnabled() {
158 StackSamplingProfiler::SetDefaultCompletedCallback(base::Bind(
159 &CallStackProfileMetricsProvider::ReceiveCompletedProfiles,
160 base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr()));
163 void CallStackProfileMetricsProvider::OnRecordingDisabled() {
164 StackSamplingProfiler::SetDefaultCompletedCallback(
165 base::Bind(&IgnoreCompletedProfiles));
166 pending_profiles_.clear();
169 void CallStackProfileMetricsProvider::ProvideGeneralMetrics(
170 ChromeUserMetricsExtension* uma_proto) {
171 DCHECK(IsSamplingProfilingReportingEnabled() || pending_profiles_.empty());
172 for (const StackSamplingProfiler::CallStackProfile& profile :
173 pending_profiles_) {
174 SampledProfile* sampled_profile = uma_proto->add_sampled_profile();
175 sampled_profile->set_trigger_event(ToSampledProfileTriggerEvent(
176 static_cast<CallStackProfileMetricsProvider::Trigger>(
177 profile.user_data)));
178 CopyProfileToProto(profile, sampled_profile->mutable_call_stack_profile());
180 pending_profiles_.clear();
183 void CallStackProfileMetricsProvider::AppendSourceProfilesForTesting(
184 const std::vector<StackSamplingProfiler::CallStackProfile>& profiles) {
185 AppendCompletedProfiles(profiles);
188 // static
189 bool CallStackProfileMetricsProvider::IsSamplingProfilingReportingEnabled() {
190 const std::string group_name = base::FieldTrialList::FindFullName(
191 CallStackProfileMetricsProvider::kFieldTrialName);
192 return group_name ==
193 CallStackProfileMetricsProvider::kReportProfilesGroupName;
196 // static
197 // Posts a message back to our own thread to collect the profiles.
198 void CallStackProfileMetricsProvider::ReceiveCompletedProfiles(
199 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
200 base::WeakPtr<CallStackProfileMetricsProvider> provider,
201 const StackSamplingProfiler::CallStackProfiles& profiles) {
202 task_runner->PostTask(
203 FROM_HERE,
204 base::Bind(&CallStackProfileMetricsProvider::AppendCompletedProfiles,
205 provider, profiles));
208 void CallStackProfileMetricsProvider::AppendCompletedProfiles(
209 const StackSamplingProfiler::CallStackProfiles& profiles) {
210 // Don't bother to record profiles if reporting is not enabled.
211 if (IsSamplingProfilingReportingEnabled()) {
212 pending_profiles_.insert(pending_profiles_.end(), profiles.begin(),
213 profiles.end());
217 } // namespace metrics