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

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

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: fixed non-windows constant 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 const ProcessPhase
Alexei Svitkine (slow) 2016/11/07 23:22:07 Please document these mappings with a comment abov
bcwhite 2016/11/08 01:02:36 Done.
37 kProtoPhases[CallStackProfileMetricsProvider::PHASES_MAX_VALUE] = {
38 ProcessPhase::MAIN_LOOP_START,
39 ProcessPhase::MAIN_NAVIGATION_START,
40 ProcessPhase::FIRST_NONEMPTY_PAINT,
41 ProcessPhase::FIRST_CONTENTFUL_PAINT,
42
43 ProcessPhase::SHUTDOWN_START,
44 };
45
46 const ProcessActivity
47 kProtoActivities[CallStackProfileMetricsProvider::ACTIVITIES_MAX_VALUE] = {
48 ProcessActivity::COLLECTING_METRICS,
49 ProcessActivity::WRITING_PROFILES_STATE,
50 };
51
36 // ProfilesState -------------------------------------------------------------- 52 // ProfilesState --------------------------------------------------------------
37 53
38 // A set of profiles and the CallStackProfileMetricsProvider state associated 54 // A set of profiles and the CallStackProfileMetricsProvider state associated
39 // with them. 55 // with them.
40 struct ProfilesState { 56 struct ProfilesState {
41 ProfilesState(const CallStackProfileParams& params, 57 ProfilesState(const CallStackProfileParams& params,
42 base::StackSamplingProfiler::CallStackProfiles profiles, 58 base::StackSamplingProfiler::CallStackProfiles profiles,
43 base::TimeTicks start_timestamp); 59 base::TimeTicks start_timestamp);
44 ProfilesState(ProfilesState&&); 60 ProfilesState(ProfilesState&&);
45 ProfilesState& operator=(ProfilesState&&); 61 ProfilesState& operator=(ProfilesState&&);
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes); 238 memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
223 return base::HashMetricName(name_bytes); 239 return base::HashMetricName(name_bytes);
224 } 240 }
225 241
226 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to 242 // Transcode |sample| into |proto_sample|, using base addresses in |modules| to
227 // compute module instruction pointer offsets. 243 // compute module instruction pointer offsets.
228 void CopySampleToProto( 244 void CopySampleToProto(
229 const StackSamplingProfiler::Sample& sample, 245 const StackSamplingProfiler::Sample& sample,
230 const std::vector<StackSamplingProfiler::Module>& modules, 246 const std::vector<StackSamplingProfiler::Module>& modules,
231 CallStackProfile::Sample* proto_sample) { 247 CallStackProfile::Sample* proto_sample) {
232 for (const StackSamplingProfiler::Frame& frame : sample) { 248 for (const StackSamplingProfiler::Frame& frame : sample.frames) {
233 CallStackProfile::Entry* entry = proto_sample->add_entry(); 249 CallStackProfile::Entry* entry = proto_sample->add_entry();
234 // A frame may not have a valid module. If so, we can't compute the 250 // A frame may not have a valid module. If so, we can't compute the
235 // instruction pointer offset, and we don't want to send bare pointers, so 251 // instruction pointer offset, and we don't want to send bare pointers, so
236 // leave call_stack_entry empty. 252 // leave call_stack_entry empty.
237 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex) 253 if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex)
238 continue; 254 continue;
239 int64_t module_offset = 255 int64_t module_offset =
240 reinterpret_cast<const char*>(frame.instruction_pointer) - 256 reinterpret_cast<const char*>(frame.instruction_pointer) -
241 reinterpret_cast<const char*>(modules[frame.module_index].base_address); 257 reinterpret_cast<const char*>(modules[frame.module_index].base_address);
242 DCHECK_GE(module_offset, 0); 258 DCHECK_GE(module_offset, 0);
243 entry->set_address(static_cast<uint64_t>(module_offset)); 259 entry->set_address(static_cast<uint64_t>(module_offset));
244 entry->set_module_id_index(frame.module_index); 260 entry->set_module_id_index(frame.module_index);
245 } 261 }
246 } 262 }
247 263
264 // Transcode Sample annotations into protobuf fields.
Alexei Svitkine (slow) 2016/11/07 23:22:07 Maybe expand the comment for the motivation - that
bcwhite 2016/11/08 01:02:36 Done.
265 void CopyAnnotationsToProto(uint32_t new_phases,
266 uint32_t activities_begun,
267 uint32_t activities_ended,
268 CallStackProfile::Sample* sample_proto) {
269 for (size_t bit = 0; new_phases != 0 && bit < sizeof(new_phases) * 8;
270 ++bit, new_phases >>= 1) {
Alexei Svitkine (slow) 2016/11/07 23:22:07 Instead of new_phases >>= 1 logic, I'd actually ju
bcwhite 2016/11/08 01:02:36 That will be two extra instructions (complement an
Alexei Svitkine (slow) 2016/11/14 18:26:39 It will only do those instructions when the bit is
bcwhite 2016/11/16 18:27:44 I think it's perfectly clear this way. But done.
271 if (new_phases & 1) {
272 if (bit >= arraysize(kProtoPhases)) {
273 NOTREACHED();
274 continue;
275 }
276 sample_proto->add_process_phase(kProtoPhases[bit]);
277 }
278 }
279
280 for (size_t bit = 0;
281 activities_begun != 0 && bit < sizeof(activities_begun) * 8;
282 ++bit, activities_begun >>= 1) {
283 if (activities_begun & 1) {
284 if (bit >= arraysize(kProtoActivities)) {
285 NOTREACHED();
286 continue;
287 }
288 sample_proto->add_activity_begun(kProtoActivities[bit]);
289 }
290 }
291
292 for (size_t bit = 0;
293 activities_ended != 0 && bit < sizeof(activities_ended) * 8;
294 ++bit, activities_ended >>= 1) {
295 if (activities_ended & 1) {
296 if (bit >= arraysize(kProtoActivities)) {
297 NOTREACHED();
298 continue;
299 }
300 sample_proto->add_activity_ended(kProtoActivities[bit]);
301 }
302 }
303 }
304
248 // Transcode |profile| into |proto_profile|. 305 // Transcode |profile| into |proto_profile|.
249 void CopyProfileToProto( 306 void CopyProfileToProto(
250 const StackSamplingProfiler::CallStackProfile& profile, 307 const StackSamplingProfiler::CallStackProfile& profile,
251 CallStackProfileParams::SampleOrderingSpec ordering_spec, 308 CallStackProfileParams::SampleOrderingSpec ordering_spec,
252 CallStackProfile* proto_profile) { 309 CallStackProfile* proto_profile) {
253 if (profile.samples.empty()) 310 if (profile.samples.empty())
254 return; 311 return;
255 312
256 if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) { 313 if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) {
257 // Collapse only consecutive repeated samples together. 314 // Collapse only consecutive repeated samples together.
258 CallStackProfile::Sample* current_sample_proto = nullptr; 315 CallStackProfile::Sample* current_sample_proto = nullptr;
316 uint32_t phases = 0;
317 uint32_t activities = 0;
259 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { 318 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
260 if (!current_sample_proto || *it != *(it - 1)) { 319 if (!current_sample_proto || *it != *(it - 1)) {
261 current_sample_proto = proto_profile->add_sample(); 320 current_sample_proto = proto_profile->add_sample();
262 CopySampleToProto(*it, profile.modules, current_sample_proto); 321 CopySampleToProto(*it, profile.modules, current_sample_proto);
263 current_sample_proto->set_count(1); 322 current_sample_proto->set_count(1);
323 CopyAnnotationsToProto(
324 it->process_phases & ~phases, // Phases are "set only".
325 it->current_activities & ~activities, // Activities can begin
326 activities & ~it->current_activities, // and end.
327 current_sample_proto);
328 phases = it->process_phases;
329 activities = it->current_activities;
264 } else { 330 } else {
265 current_sample_proto->set_count(current_sample_proto->count() + 1); 331 current_sample_proto->set_count(current_sample_proto->count() + 1);
266 } 332 }
267 } 333 }
268 } else { 334 } else {
269 // Collapse all repeated samples together. 335 // Collapse all repeated samples together.
270 std::map<StackSamplingProfiler::Sample, int> sample_index; 336 std::map<StackSamplingProfiler::Sample, int> sample_index;
271 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) { 337 for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
272 auto location = sample_index.find(*it); 338 auto location = sample_index.find(*it);
273 if (location == sample_index.end()) { 339 if (location == sample_index.end()) {
274 CallStackProfile::Sample* sample_proto = proto_profile->add_sample(); 340 CallStackProfile::Sample* sample_proto = proto_profile->add_sample();
275 CopySampleToProto(*it, profile.modules, sample_proto); 341 CopySampleToProto(*it, profile.modules, sample_proto);
276 sample_proto->set_count(1); 342 sample_proto->set_count(1);
343 CopyAnnotationsToProto(it->process_phases, it->current_activities, 0,
344 sample_proto);
277 sample_index.insert( 345 sample_index.insert(
278 std::make_pair( 346 std::make_pair(
279 *it, static_cast<int>(proto_profile->sample().size()) - 1)); 347 *it, static_cast<int>(proto_profile->sample().size()) - 1));
280 } else { 348 } else {
281 CallStackProfile::Sample* sample_proto = 349 CallStackProfile::Sample* sample_proto =
282 proto_profile->mutable_sample()->Mutable(location->second); 350 proto_profile->mutable_sample()->Mutable(location->second);
283 sample_proto->set_count(sample_proto->count() + 1); 351 sample_proto->set_count(sample_proto->count() + 1);
284 } 352 }
285 } 353 }
286 } 354 }
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 517
450 // static 518 // static
451 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() { 519 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() {
452 const std::string group_name = base::FieldTrialList::FindFullName( 520 const std::string group_name = base::FieldTrialList::FindFullName(
453 CallStackProfileMetricsProvider::kFieldTrialName); 521 CallStackProfileMetricsProvider::kFieldTrialName);
454 return group_name == 522 return group_name ==
455 CallStackProfileMetricsProvider::kReportProfilesGroupName; 523 CallStackProfileMetricsProvider::kReportProfilesGroupName;
456 } 524 }
457 525
458 } // namespace metrics 526 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698