Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |