Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(397)

Side by Side Diff: components/metrics/call_stack_profile_metrics_provider.cc

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: addressed review comments and finished converting tests Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/metrics/call_stack_profile_metrics_provider.h" 5 #include "components/metrics/call_stack_profile_metrics_provider.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 15 matching lines...) Expand all
26 #include "base/threading/thread_task_runner_handle.h" 26 #include "base/threading/thread_task_runner_handle.h"
27 #include "base/time/time.h" 27 #include "base/time/time.h"
28 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h" 28 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
29 29
30 using base::StackSamplingProfiler; 30 using base::StackSamplingProfiler;
31 31
32 namespace metrics { 32 namespace metrics {
33 33
34 namespace { 34 namespace {
35 35
36 // Provide a mapping from the C++ "enum" definition of various process phases
37 // to the equivalent protobuf "enum" definition. This table-lookup conversion
38 // allows for the implementation to evolve and still be compatible with the
39 // protobuf -- even if there are ever more than 32 defined proto values, though
40 // never more than 32 could be in-use in a given C++ version of the code.
41 const ProcessPhase
42 kProtoPhases[CallStackProfileMetricsProvider::PHASES_MAX_VALUE] = {
43 ProcessPhase::MAIN_LOOP_START,
44 ProcessPhase::MAIN_NAVIGATION_START,
45 ProcessPhase::MAIN_NAVIGATION_FINISHED,
46 ProcessPhase::FIRST_NONEMPTY_PAINT,
47
48 ProcessPhase::SHUTDOWN_START,
49 };
50
36 // ProfilesState -------------------------------------------------------------- 51 // ProfilesState --------------------------------------------------------------
37 52
38 // A set of profiles and the CallStackProfileMetricsProvider state associated 53 // A set of profiles and the CallStackProfileMetricsProvider state associated
39 // with them. 54 // with them.
40 struct ProfilesState { 55 struct ProfilesState {
41 ProfilesState(const CallStackProfileParams& params, 56 ProfilesState(const CallStackProfileParams& params,
42 base::StackSamplingProfiler::CallStackProfiles profiles, 57 base::StackSamplingProfiler::CallStackProfiles profiles,
43 base::TimeTicks start_timestamp); 58 base::TimeTicks start_timestamp);
44 ProfilesState(ProfilesState&&); 59 ProfilesState(ProfilesState&&);
45 ProfilesState& operator=(ProfilesState&&); 60 ProfilesState& operator=(ProfilesState&&);
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes); 231 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
217 return base::HashMetricName(name_bytes); 232 return base::HashMetricName(name_bytes);
218 } 233 }
219 234
220 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to 235 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to
221 // compute module instruction pointer offsets. 236 // compute module instruction pointer offsets.
222 void CopySampleToProto( 237 void CopySampleToProto(
223 const StackSamplingProfiler::Sample& sample, 238 const StackSamplingProfiler::Sample& sample,
224 const std::vector<StackSamplingProfiler::Module>& modules, 239 const std::vector<StackSamplingProfiler::Module>& modules,
225 CallStackProfile::Sample* proto_sample) { 240 CallStackProfile::Sample* proto_sample) {
226 for (const StackSamplingProfiler::Frame& frame : sample) { 241 for (const StackSamplingProfiler::Frame& frame : sample.frames) {
227 CallStackProfile::Entry* entry = proto_sample->add_entry(); 242 CallStackProfile::Entry* entry = proto_sample->add_entry();
228 // A frame may not have a valid module. If so, we can't compute the 243 // A frame may not have a valid module. If so, we can't compute the
229 // instruction pointer offset, and we don't want to send bare pointers, so 244 // instruction pointer offset, and we don't want to send bare pointers, so
230 // leave call_stack_entry empty. 245 // leave call_stack_entry empty.
231 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex) 246 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex)
232 continue; 247 continue;
233 int64_t module_offset = 248 int64_t module_offset =
234 reinterpret_cast<const char*>(frame.instruction_pointer) - 249 reinterpret_cast<const char*>(frame.instruction_pointer) -
235 reinterpret_cast<const char*>(modules[frame.module_index].base_address); 250 reinterpret_cast<const char*>(modules[frame.module_index].base_address);
236 DCHECK_GE(module_offset, 0); 251 DCHECK_GE(module_offset, 0);
237 entry->set_address(static_cast<uint64_t>(module_offset)); 252 entry->set_address(static_cast<uint64_t>(module_offset));
238 entry->set_module_id_index(frame.module_index); 253 entry->set_module_id_index(frame.module_index);
239 } 254 }
240 } 255 }
241 256
257 // Transcode Sample annotations into protobuf fields. The C++ code uses a bit-
258 // field with each bit correspondirg to an entry in an enumeration while the
Mike Wittman 2016/11/16 22:36:09 nit: corresponding
bcwhite 2016/11/16 23:10:49 Done.
259 // protobuf uses a repeated field of individual values. Conversion tables
260 // allow for arbitrary mapping, though no more than 32 in any given version
261 // of the code.
262 void CopyAnnotationsToProto(uint32_t new_phases,
263 CallStackProfile::Sample* sample_proto) {
264 for (size_t bit = 0; new_phases != 0 && bit < sizeof(new_phases) * 8; ++bit) {
265 const uint32_t flag = 1U << bit;
266 if (new_phases & flag) {
267 if (bit >= arraysize(kProtoPhases)) {
268 NOTREACHED();
269 continue;
270 }
271 sample_proto->add_process_phase(kProtoPhases[bit]);
272 new_phases ^= flag; // Bit is set so XOR will clear it.
273 }
274 }
275 }
276
242 // Transcode |profile| into |proto_profile|. 277 // Transcode |profile| into |proto_profile|.
243 void CopyProfileToProto( 278 void CopyProfileToProto(
244 const StackSamplingProfiler::CallStackProfile& profile, 279 const StackSamplingProfiler::CallStackProfile& profile,
245 CallStackProfileParams::SampleOrderingSpec ordering_spec, 280 CallStackProfileParams::SampleOrderingSpec ordering_spec,
246 CallStackProfile* proto_profile) { 281 CallStackProfile* proto_profile) {
247 if (profile.samples.empty()) 282 if (profile.samples.empty())
248 return; 283 return;
249 284
250 if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) { 285 if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) {
251 // Collapse only consecutive repeated samples together. 286 // Collapse only consecutive repeated samples together.
252 CallStackProfile::Sample* current_sample_proto = nullptr; 287 CallStackProfile::Sample* current_sample_proto = nullptr;
288 uint32_t phases = 0;
253 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { 289 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
254 if (!current_sample_proto || *it != *(it - 1)) { 290 if (!current_sample_proto || *it != *(it - 1)) {
255 current_sample_proto = proto_profile->add_sample(); 291 current_sample_proto = proto_profile->add_sample();
256 CopySampleToProto(*it, profile.modules, current_sample_proto); 292 CopySampleToProto(*it, profile.modules, current_sample_proto);
257 current_sample_proto->set_count(1); 293 current_sample_proto->set_count(1);
294 CopyAnnotationsToProto(it->process_phases & ~phases,
295 current_sample_proto);
296 phases = it->process_phases;
258 } else { 297 } else {
259 current_sample_proto->set_count(current_sample_proto->count() + 1); 298 current_sample_proto->set_count(current_sample_proto->count() + 1);
260 } 299 }
261 } 300 }
262 } else { 301 } else {
263 // Collapse all repeated samples together. 302 // Collapse all repeated samples together.
264 std::map<StackSamplingProfiler::Sample, int> sample_index; 303 std::map<StackSamplingProfiler::Sample, int> sample_index;
265 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { 304 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
266 auto location = sample_index.find(*it); 305 auto location = sample_index.find(*it);
Alexei Svitkine (slow) 2016/11/16 19:10:24 This doesn't need any extra logic to split samples
Mike Wittman 2016/11/16 22:36:09 I believe this does need to split samples based on
bcwhite 2016/11/16 23:10:49 Done.
bcwhite 2016/11/16 23:10:49 Splitting on phase is already done because, as Ale
267 if (location == sample_index.end()) { 306 if (location == sample_index.end()) {
268 CallStackProfile::Sample* sample_proto = proto_profile->add_sample(); 307 CallStackProfile::Sample* sample_proto = proto_profile->add_sample();
269 CopySampleToProto(*it, profile.modules, sample_proto); 308 CopySampleToProto(*it, profile.modules, sample_proto);
270 sample_proto->set_count(1); 309 sample_proto->set_count(1);
310 CopyAnnotationsToProto(it->process_phases, sample_proto);
271 sample_index.insert( 311 sample_index.insert(
272 std::make_pair( 312 std::make_pair(
273 *it, static_cast<int>(proto_profile->sample().size()) - 1)); 313 *it, static_cast<int>(proto_profile->sample().size()) - 1));
274 } else { 314 } else {
275 CallStackProfile::Sample* sample_proto = 315 CallStackProfile::Sample* sample_proto =
276 proto_profile->mutable_sample()->Mutable(location->second); 316 proto_profile->mutable_sample()->Mutable(location->second);
277 sample_proto->set_count(sample_proto->count() + 1); 317 sample_proto->set_count(sample_proto->count() + 1);
278 } 318 }
279 } 319 }
280 } 320 }
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 483
444 // static 484 // static
445 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() { 485 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() {
446 const std::string group_name = base::FieldTrialList::FindFullName( 486 const std::string group_name = base::FieldTrialList::FindFullName(
447 CallStackProfileMetricsProvider::kFieldTrialName); 487 CallStackProfileMetricsProvider::kFieldTrialName);
448 return group_name == 488 return group_name ==
449 CallStackProfileMetricsProvider::kReportProfilesGroupName; 489 CallStackProfileMetricsProvider::kReportProfilesGroupName;
450 } 490 }
451 491
452 } // namespace metrics 492 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698