Prevent app list doodle from being pinch-to-zoomed.
[chromium-blink-merge.git] / components / metrics / call_stack_profile_metrics_provider.cc
blob1ebff3e80fcd8a999c24a2b33bcf27fff3f20156
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/logging.h"
13 #include "base/macros.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/profiler/stack_sampling_profiler.h"
17 #include "components/metrics/metrics_hashes.h"
18 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
20 using base::StackSamplingProfiler;
22 namespace metrics {
24 namespace {
26 // Accepts and ignores the completed profiles. Used when metrics reporting is
27 // disabled.
28 void IgnoreCompletedProfiles(
29 const StackSamplingProfiler::CallStackProfiles& profiles) {
32 // The protobuf expects the MD5 checksum prefix of the module name.
33 uint64 HashModuleFilename(const base::FilePath& filename) {
34 const base::FilePath::StringType basename = filename.BaseName().value();
35 // Copy the bytes in basename into a string buffer.
36 size_t basename_length_in_bytes =
37 basename.size() * sizeof(base::FilePath::CharType);
38 std::string name_bytes(basename_length_in_bytes, '\0');
39 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
40 return HashMetricName(name_bytes);
43 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to
44 // compute module instruction pointer offsets.
45 void CopySampleToProto(
46 const StackSamplingProfiler::Sample& sample,
47 const std::vector<StackSamplingProfiler::Module>& modules,
48 CallStackProfile::Sample* proto_sample) {
49 for (const StackSamplingProfiler::Frame& frame : sample) {
50 CallStackProfile::Entry* entry = proto_sample->add_entry();
51 // A frame may not have a valid module. If so, we can't compute the
52 // instruction pointer offset, and we don't want to send bare pointers, so
53 // leave call_stack_entry empty.
54 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex)
55 continue;
56 int64 module_offset =
57 reinterpret_cast<const char*>(frame.instruction_pointer) -
58 reinterpret_cast<const char*>(modules[frame.module_index].base_address);
59 DCHECK_GE(module_offset, 0);
60 entry->set_address(static_cast<uint64>(module_offset));
61 entry->set_module_id_index(frame.module_index);
65 // Transcode |profile| into |proto_profile|.
66 void CopyProfileToProto(
67 const StackSamplingProfiler::CallStackProfile& profile,
68 CallStackProfile* proto_profile) {
69 if (profile.samples.empty())
70 return;
72 if (profile.preserve_sample_ordering) {
73 // Collapse only consecutive repeated samples together.
74 CallStackProfile::Sample* current_sample_proto = nullptr;
75 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
76 if (!current_sample_proto || *it != *(it - 1)) {
77 current_sample_proto = proto_profile->add_sample();
78 CopySampleToProto(*it, profile.modules, current_sample_proto);
79 current_sample_proto->set_count(1);
80 } else {
81 current_sample_proto->set_count(current_sample_proto->count() + 1);
84 } else {
85 // Collapse all repeated samples together.
86 std::map<StackSamplingProfiler::Sample, int> sample_index;
87 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
88 auto location = sample_index.find(*it);
89 if (location == sample_index.end()) {
90 CallStackProfile::Sample* sample_proto = proto_profile->add_sample();
91 CopySampleToProto(*it, profile.modules, sample_proto);
92 sample_proto->set_count(1);
93 sample_index.insert(
94 std::make_pair(
95 *it, static_cast<int>(proto_profile->sample().size()) - 1));
96 } else {
97 CallStackProfile::Sample* sample_proto =
98 proto_profile->mutable_sample()->Mutable(location->second);
99 sample_proto->set_count(sample_proto->count() + 1);
104 for (const StackSamplingProfiler::Module& module : profile.modules) {
105 CallStackProfile::ModuleIdentifier* module_id =
106 proto_profile->add_module_id();
107 module_id->set_build_id(module.id);
108 module_id->set_name_md5_prefix(HashModuleFilename(module.filename));
111 proto_profile->set_profile_duration_ms(
112 profile.profile_duration.InMilliseconds());
113 proto_profile->set_sampling_period_ms(
114 profile.sampling_period.InMilliseconds());
117 // Translates CallStackProfileMetricsProvider's trigger to the corresponding
118 // SampledProfile TriggerEvent.
119 SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
120 CallStackProfileMetricsProvider::Trigger trigger) {
121 switch (trigger) {
122 case CallStackProfileMetricsProvider::UNKNOWN:
123 return SampledProfile::UNKNOWN_TRIGGER_EVENT;
124 break;
125 case CallStackProfileMetricsProvider::PROCESS_STARTUP:
126 return SampledProfile::PROCESS_STARTUP;
127 break;
128 case CallStackProfileMetricsProvider::JANKY_TASK:
129 return SampledProfile::JANKY_TASK;
130 break;
131 case CallStackProfileMetricsProvider::THREAD_HUNG:
132 return SampledProfile::THREAD_HUNG;
133 break;
135 NOTREACHED();
136 return SampledProfile::UNKNOWN_TRIGGER_EVENT;
139 } // namespace
141 const char CallStackProfileMetricsProvider::kFieldTrialName[] =
142 "StackProfiling";
143 const char CallStackProfileMetricsProvider::kReportProfilesGroupName[] =
144 "Report profiles";
146 CallStackProfileMetricsProvider::CallStackProfileMetricsProvider()
147 : weak_factory_(this) {
150 CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {
151 StackSamplingProfiler::SetDefaultCompletedCallback(
152 StackSamplingProfiler::CompletedCallback());
155 void CallStackProfileMetricsProvider::OnRecordingEnabled() {
156 StackSamplingProfiler::SetDefaultCompletedCallback(
157 base::Bind(&CallStackProfileMetricsProvider::ReceiveCompletedProfiles,
158 base::MessageLoopProxy::current(),
159 weak_factory_.GetWeakPtr()));
162 void CallStackProfileMetricsProvider::OnRecordingDisabled() {
163 StackSamplingProfiler::SetDefaultCompletedCallback(
164 base::Bind(&IgnoreCompletedProfiles));
165 pending_profiles_.clear();
168 void CallStackProfileMetricsProvider::ProvideGeneralMetrics(
169 ChromeUserMetricsExtension* uma_proto) {
170 DCHECK(IsSamplingProfilingReportingEnabled() || pending_profiles_.empty());
171 for (const StackSamplingProfiler::CallStackProfile& profile :
172 pending_profiles_) {
173 SampledProfile* sampled_profile = uma_proto->add_sampled_profile();
174 sampled_profile->set_trigger_event(ToSampledProfileTriggerEvent(
175 static_cast<CallStackProfileMetricsProvider::Trigger>(
176 profile.user_data)));
177 CopyProfileToProto(profile, sampled_profile->mutable_call_stack_profile());
179 pending_profiles_.clear();
182 void CallStackProfileMetricsProvider::AppendSourceProfilesForTesting(
183 const std::vector<StackSamplingProfiler::CallStackProfile>& profiles) {
184 AppendCompletedProfiles(profiles);
187 // static
188 bool CallStackProfileMetricsProvider::IsSamplingProfilingReportingEnabled() {
189 const std::string group_name = base::FieldTrialList::FindFullName(
190 CallStackProfileMetricsProvider::kFieldTrialName);
191 return group_name ==
192 CallStackProfileMetricsProvider::kReportProfilesGroupName;
195 // static
196 // Posts a message back to our own thread to collect the profiles.
197 void CallStackProfileMetricsProvider::ReceiveCompletedProfiles(
198 scoped_refptr<base::MessageLoopProxy> message_loop,
199 base::WeakPtr<CallStackProfileMetricsProvider> provider,
200 const StackSamplingProfiler::CallStackProfiles& profiles) {
201 message_loop->PostTask(
202 FROM_HERE,
203 base::Bind(&CallStackProfileMetricsProvider::AppendCompletedProfiles,
204 provider, profiles));
207 void CallStackProfileMetricsProvider::AppendCompletedProfiles(
208 const StackSamplingProfiler::CallStackProfiles& profiles) {
209 // Don't bother to record profiles if reporting is not enabled.
210 if (IsSamplingProfilingReportingEnabled()) {
211 pending_profiles_.insert(pending_profiles_.end(), profiles.begin(),
212 profiles.end());
216 } // namespace metrics