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> |
11 #include <cstring> | 11 #include <cstring> |
12 #include <map> | 12 #include <map> |
13 #include <string> | 13 #include <string> |
14 #include <utility> | 14 #include <utility> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "base/bind.h" | 17 #include "base/bind.h" |
18 #include "base/location.h" | 18 #include "base/location.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/macros.h" | 20 #include "base/macros.h" |
21 #include "base/memory/singleton.h" | 21 #include "base/memory/singleton.h" |
22 #include "base/metrics/field_trial.h" | 22 #include "base/metrics/field_trial_params.h" |
23 #include "base/metrics/metrics_hashes.h" | 23 #include "base/metrics/metrics_hashes.h" |
24 #include "base/profiler/stack_sampling_profiler.h" | 24 #include "base/profiler/stack_sampling_profiler.h" |
25 #include "base/single_thread_task_runner.h" | 25 #include "base/single_thread_task_runner.h" |
26 #include "base/synchronization/lock.h" | 26 #include "base/synchronization/lock.h" |
27 #include "base/threading/thread_task_runner_handle.h" | 27 #include "base/threading/thread_task_runner_handle.h" |
28 #include "base/time/time.h" | 28 #include "base/time/time.h" |
29 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h" | 29 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h" |
30 | 30 |
31 using base::StackSamplingProfiler; | 31 using base::StackSamplingProfiler; |
32 | 32 |
(...skipping 16 matching lines...) Expand all Loading... | |
49 | 49 |
50 ProcessPhase::SHUTDOWN_START, | 50 ProcessPhase::SHUTDOWN_START, |
51 }; | 51 }; |
52 | 52 |
53 // ProfilesState -------------------------------------------------------------- | 53 // ProfilesState -------------------------------------------------------------- |
54 | 54 |
55 // A set of profiles and the CallStackProfileMetricsProvider state associated | 55 // A set of profiles and the CallStackProfileMetricsProvider state associated |
56 // with them. | 56 // with them. |
57 struct ProfilesState { | 57 struct ProfilesState { |
58 ProfilesState(const CallStackProfileParams& params, | 58 ProfilesState(const CallStackProfileParams& params, |
59 StackSamplingProfiler::CallStackProfiles profiles, | 59 StackSamplingProfiler::CallStackProfiles profiles); |
60 base::TimeTicks start_timestamp); | |
61 ProfilesState(ProfilesState&&); | 60 ProfilesState(ProfilesState&&); |
62 ProfilesState& operator=(ProfilesState&&); | 61 ProfilesState& operator=(ProfilesState&&); |
63 | 62 |
64 // The metrics-related parameters provided to | 63 // The metrics-related parameters provided to |
65 // CallStackProfileMetricsProvider::GetProfilerCallback(). | 64 // CallStackProfileMetricsProvider::GetProfilerCallback(). |
66 CallStackProfileParams params; | 65 CallStackProfileParams params; |
67 | 66 |
68 // The call stack profiles collected by the profiler. | 67 // The call stack profiles collected by the profiler. |
69 StackSamplingProfiler::CallStackProfiles profiles; | 68 StackSamplingProfiler::CallStackProfiles profiles; |
70 | 69 |
71 // The time at which the CallStackProfileMetricsProvider became aware of the | |
72 // request for profiling. In particular, this is when callback was requested | |
73 // via CallStackProfileMetricsProvider::GetProfilerCallback(). Used to | |
74 // determine if collection was disabled during the collection of the profile. | |
75 base::TimeTicks start_timestamp; | |
76 | |
77 private: | 70 private: |
78 DISALLOW_COPY_AND_ASSIGN(ProfilesState); | 71 DISALLOW_COPY_AND_ASSIGN(ProfilesState); |
79 }; | 72 }; |
80 | 73 |
81 ProfilesState::ProfilesState(const CallStackProfileParams& params, | 74 ProfilesState::ProfilesState(const CallStackProfileParams& params, |
82 StackSamplingProfiler::CallStackProfiles profiles, | 75 StackSamplingProfiler::CallStackProfiles profiles) |
83 base::TimeTicks start_timestamp) | 76 : params(params), profiles(std::move(profiles)) {} |
84 : params(params), | |
85 profiles(std::move(profiles)), | |
86 start_timestamp(start_timestamp) {} | |
87 | 77 |
88 ProfilesState::ProfilesState(ProfilesState&&) = default; | 78 ProfilesState::ProfilesState(ProfilesState&&) = default; |
89 | 79 |
90 // Some versions of GCC need this for push_back to work with std::move. | 80 // Some versions of GCC need this for push_back to work with std::move. |
91 ProfilesState& ProfilesState::operator=(ProfilesState&&) = default; | 81 ProfilesState& ProfilesState::operator=(ProfilesState&&) = default; |
92 | 82 |
93 // PendingProfiles ------------------------------------------------------------ | 83 // PendingProfiles ------------------------------------------------------------ |
94 | 84 |
95 // Singleton class responsible for retaining profiles received via the callback | 85 // Singleton class responsible for retaining profiles received via the callback |
96 // created by CallStackProfileMetricsProvider::GetProfilerCallback(). These are | 86 // created by CallStackProfileMetricsProvider::GetProfilerCallback(). These are |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 } | 163 } |
174 | 164 |
175 void PendingProfiles::CollectProfilesIfCollectionEnabled( | 165 void PendingProfiles::CollectProfilesIfCollectionEnabled( |
176 ProfilesState profiles) { | 166 ProfilesState profiles) { |
177 base::AutoLock scoped_lock(lock_); | 167 base::AutoLock scoped_lock(lock_); |
178 | 168 |
179 // Only collect if collection is not disabled and hasn't been disabled | 169 // Only collect if collection is not disabled and hasn't been disabled |
180 // since the start of collection for this profile. | 170 // since the start of collection for this profile. |
181 if (!collection_enabled_ || | 171 if (!collection_enabled_ || |
182 (!last_collection_disable_time_.is_null() && | 172 (!last_collection_disable_time_.is_null() && |
183 last_collection_disable_time_ >= profiles.start_timestamp)) { | 173 last_collection_disable_time_ >= profiles.params.start_timestamp)) { |
184 return; | 174 return; |
185 } | 175 } |
186 | 176 |
187 profiles_.push_back(std::move(profiles)); | 177 profiles_.push_back(std::move(profiles)); |
188 } | 178 } |
189 | 179 |
190 void PendingProfiles::ResetToDefaultStateForTesting() { | 180 void PendingProfiles::ResetToDefaultStateForTesting() { |
191 base::AutoLock scoped_lock(lock_); | 181 base::AutoLock scoped_lock(lock_); |
192 | 182 |
193 collection_enabled_ = true; | 183 collection_enabled_ = true; |
194 last_collection_disable_time_ = base::TimeTicks(); | 184 last_collection_disable_time_ = base::TimeTicks(); |
195 profiles_.clear(); | 185 profiles_.clear(); |
196 } | 186 } |
197 | 187 |
198 // |collection_enabled_| is initialized to true to collect any profiles that are | 188 // |collection_enabled_| is initialized to true to collect any profiles that are |
199 // generated prior to creation of the CallStackProfileMetricsProvider. The | 189 // generated prior to creation of the CallStackProfileMetricsProvider. The |
200 // ultimate disposition of these pre-creation collected profiles will be | 190 // ultimate disposition of these pre-creation collected profiles will be |
201 // determined by the initial recording state provided to | 191 // determined by the initial recording state provided to |
202 // CallStackProfileMetricsProvider. | 192 // CallStackProfileMetricsProvider. |
203 PendingProfiles::PendingProfiles() : collection_enabled_(true) {} | 193 PendingProfiles::PendingProfiles() : collection_enabled_(true) {} |
204 | 194 |
205 PendingProfiles::~PendingProfiles() {} | 195 PendingProfiles::~PendingProfiles() {} |
206 | 196 |
207 // Functions to process completed profiles ------------------------------------ | 197 // Functions to process completed profiles ------------------------------------ |
208 | 198 |
209 // Will be invoked on either the main thread or the profiler's thread. Provides | 199 // Will be invoked on either the main thread or the profiler's thread. Provides |
210 // the profiles to PendingProfiles to append, if the collecting state allows. | 200 // the profiles to PendingProfiles to append, if the collecting state allows. |
211 void ReceiveCompletedProfilesImpl( | 201 bool ReceiveCompletedProfilesImpl( |
212 const CallStackProfileParams& params, | 202 CallStackProfileParams* params, |
213 base::TimeTicks start_timestamp, | 203 StackSamplingProfiler::CallStackProfiles profiles, |
214 StackSamplingProfiler::CallStackProfiles profiles) { | 204 StackSamplingProfiler::SamplingParams* sampling_params) { |
215 PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled( | 205 PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled( |
216 ProfilesState(params, std::move(profiles), start_timestamp)); | 206 ProfilesState(*params, std::move(profiles))); |
207 | |
208 // Now, schedule periodic sampling every 1s, if enabled by trial. | |
209 if (sampling_params && | |
210 CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled() && | |
211 params->process == CallStackProfileParams::BROWSER_PROCESS && | |
212 params->thread == CallStackProfileParams::UI_THREAD) { | |
213 params->trigger = metrics::CallStackProfileParams::PERIODIC_COLLECTION; | |
214 params->start_timestamp = base::TimeTicks::Now(); | |
215 sampling_params->initial_delay = base::TimeDelta::FromSeconds(1); | |
216 sampling_params->bursts = 1; | |
217 sampling_params->samples_per_burst = 1; | |
218 // Below are unused: | |
219 sampling_params->burst_interval = base::TimeDelta::FromMilliseconds(0); | |
220 sampling_params->sampling_interval = base::TimeDelta::FromMilliseconds(0); | |
221 return true; | |
222 } | |
223 return false; | |
217 } | 224 } |
218 | 225 |
219 // Invoked on an arbitrary thread. Ignores the provided profiles. | 226 // Invoked on an arbitrary thread. Ignores the provided profiles. |
220 void IgnoreCompletedProfiles( | 227 bool IgnoreCompletedProfiles( |
221 StackSamplingProfiler::CallStackProfiles profiles) {} | 228 StackSamplingProfiler::CallStackProfiles profiles, |
229 StackSamplingProfiler::SamplingParams* sampling_params) { | |
230 return false; | |
231 } | |
222 | 232 |
223 // Functions to encode protobufs ---------------------------------------------- | 233 // Functions to encode protobufs ---------------------------------------------- |
224 | 234 |
225 // The protobuf expects the MD5 checksum prefix of the module name. | 235 // The protobuf expects the MD5 checksum prefix of the module name. |
226 uint64_t HashModuleFilename(const base::FilePath& filename) { | 236 uint64_t HashModuleFilename(const base::FilePath& filename) { |
227 const base::FilePath::StringType basename = filename.BaseName().value(); | 237 const base::FilePath::StringType basename = filename.BaseName().value(); |
228 // Copy the bytes in basename into a string buffer. | 238 // Copy the bytes in basename into a string buffer. |
229 size_t basename_length_in_bytes = | 239 size_t basename_length_in_bytes = |
230 basename.size() * sizeof(base::FilePath::CharType); | 240 basename.size() * sizeof(base::FilePath::CharType); |
231 std::string name_bytes(basename_length_in_bytes, '\0'); | 241 std::string name_bytes(basename_length_in_bytes, '\0'); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 for (const StackSamplingProfiler::Module& module : profile.modules) { | 334 for (const StackSamplingProfiler::Module& module : profile.modules) { |
325 CallStackProfile::ModuleIdentifier* module_id = | 335 CallStackProfile::ModuleIdentifier* module_id = |
326 proto_profile->add_module_id(); | 336 proto_profile->add_module_id(); |
327 module_id->set_build_id(module.id); | 337 module_id->set_build_id(module.id); |
328 module_id->set_name_md5_prefix(HashModuleFilename(module.filename)); | 338 module_id->set_name_md5_prefix(HashModuleFilename(module.filename)); |
329 } | 339 } |
330 | 340 |
331 proto_profile->set_profile_duration_ms( | 341 proto_profile->set_profile_duration_ms( |
332 profile.profile_duration.InMilliseconds()); | 342 profile.profile_duration.InMilliseconds()); |
333 proto_profile->set_sampling_period_ms( | 343 proto_profile->set_sampling_period_ms( |
334 profile.sampling_period.InMilliseconds()); | 344 profile.sampling_period.InMilliseconds()); |
Alexei Svitkine (slow)
2017/06/20 20:57:39
Note: I need to double check whether sampling peri
Mike Wittman
2017/06/21 14:49:06
The sampling period is being set correctly, but th
Alexei Svitkine (slow)
2017/06/29 20:51:04
Done.
| |
335 } | 345 } |
336 | 346 |
337 // Translates CallStackProfileParams's process to the corresponding | 347 // Translates CallStackProfileParams's process to the corresponding |
338 // execution context Process. | 348 // execution context Process. |
339 Process ToExecutionContextProcess(CallStackProfileParams::Process process) { | 349 Process ToExecutionContextProcess(CallStackProfileParams::Process process) { |
340 switch (process) { | 350 switch (process) { |
341 case CallStackProfileParams::UNKNOWN_PROCESS: | 351 case CallStackProfileParams::UNKNOWN_PROCESS: |
342 return UNKNOWN_PROCESS; | 352 return UNKNOWN_PROCESS; |
343 case CallStackProfileParams::BROWSER_PROCESS: | 353 case CallStackProfileParams::BROWSER_PROCESS: |
344 return BROWSER_PROCESS; | 354 return BROWSER_PROCESS; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
398 CallStackProfileParams::Trigger trigger) { | 408 CallStackProfileParams::Trigger trigger) { |
399 switch (trigger) { | 409 switch (trigger) { |
400 case CallStackProfileParams::UNKNOWN: | 410 case CallStackProfileParams::UNKNOWN: |
401 return SampledProfile::UNKNOWN_TRIGGER_EVENT; | 411 return SampledProfile::UNKNOWN_TRIGGER_EVENT; |
402 case CallStackProfileParams::PROCESS_STARTUP: | 412 case CallStackProfileParams::PROCESS_STARTUP: |
403 return SampledProfile::PROCESS_STARTUP; | 413 return SampledProfile::PROCESS_STARTUP; |
404 case CallStackProfileParams::JANKY_TASK: | 414 case CallStackProfileParams::JANKY_TASK: |
405 return SampledProfile::JANKY_TASK; | 415 return SampledProfile::JANKY_TASK; |
406 case CallStackProfileParams::THREAD_HUNG: | 416 case CallStackProfileParams::THREAD_HUNG: |
407 return SampledProfile::THREAD_HUNG; | 417 return SampledProfile::THREAD_HUNG; |
418 case CallStackProfileParams::PERIODIC_COLLECTION: | |
419 return SampledProfile::PERIODIC_COLLECTION; | |
408 } | 420 } |
409 NOTREACHED(); | 421 NOTREACHED(); |
410 return SampledProfile::UNKNOWN_TRIGGER_EVENT; | 422 return SampledProfile::UNKNOWN_TRIGGER_EVENT; |
411 } | 423 } |
412 | 424 |
413 } // namespace | 425 } // namespace |
414 | 426 |
415 // CallStackProfileMetricsProvider -------------------------------------------- | 427 // CallStackProfileMetricsProvider -------------------------------------------- |
416 | 428 |
417 const char CallStackProfileMetricsProvider::kFieldTrialName[] = | 429 const base::Feature CallStackProfileMetricsProvider::kEnableReporting = { |
418 "StackProfiling"; | 430 "SamplingProfilerReporting", base::FEATURE_DISABLED_BY_DEFAULT}; |
419 const char CallStackProfileMetricsProvider::kReportProfilesGroupName[] = | |
420 "Report profiles"; | |
421 | 431 |
422 CallStackProfileMetricsProvider::CallStackProfileMetricsProvider() { | 432 CallStackProfileMetricsProvider::CallStackProfileMetricsProvider() { |
423 } | 433 } |
424 | 434 |
425 CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() { | 435 CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() { |
426 } | 436 } |
427 | 437 |
428 // This function can be invoked on an abitrary thread. | 438 // This function can be invoked on an abitrary thread. |
429 StackSamplingProfiler::CompletedCallback | 439 StackSamplingProfiler::CompletedCallback |
430 CallStackProfileMetricsProvider::GetProfilerCallback( | 440 CallStackProfileMetricsProvider::GetProfilerCallback( |
431 const CallStackProfileParams& params) { | 441 CallStackProfileParams* params) { |
432 // Ignore the profiles if the collection is disabled. If the collection state | 442 // Ignore the profiles if the collection is disabled. If the collection state |
433 // changes while collecting, this will be detected by the callback and | 443 // changes while collecting, this will be detected by the callback and |
434 // profiles will be ignored at that point. | 444 // profiles will be ignored at that point. |
435 if (!PendingProfiles::GetInstance()->IsCollectionEnabled()) | 445 if (!PendingProfiles::GetInstance()->IsCollectionEnabled()) |
436 return base::Bind(&IgnoreCompletedProfiles); | 446 return base::Bind(&IgnoreCompletedProfiles); |
437 | 447 |
438 return base::Bind(&ReceiveCompletedProfilesImpl, params, | 448 params->start_timestamp = base::TimeTicks::Now(); |
439 base::TimeTicks::Now()); | 449 return base::Bind(&ReceiveCompletedProfilesImpl, params); |
440 } | 450 } |
441 | 451 |
442 // static | 452 // static |
443 void CallStackProfileMetricsProvider::ReceiveCompletedProfiles( | 453 void CallStackProfileMetricsProvider::ReceiveCompletedProfiles( |
444 const CallStackProfileParams& params, | 454 CallStackProfileParams* params, |
445 base::TimeTicks start_timestamp, | 455 base::StackSamplingProfiler::CallStackProfiles profiles) { |
446 StackSamplingProfiler::CallStackProfiles profiles) { | 456 ReceiveCompletedProfilesImpl(params, std::move(profiles), nullptr); |
447 ReceiveCompletedProfilesImpl(params, start_timestamp, std::move(profiles)); | 457 } |
458 | |
459 // static | |
460 bool CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled() { | |
461 return base::GetFieldTrialParamByFeatureAsBool(kEnableReporting, "periodic", | |
462 false); | |
448 } | 463 } |
449 | 464 |
450 void CallStackProfileMetricsProvider::OnRecordingEnabled() { | 465 void CallStackProfileMetricsProvider::OnRecordingEnabled() { |
451 PendingProfiles::GetInstance()->SetCollectionEnabled(true); | 466 PendingProfiles::GetInstance()->SetCollectionEnabled(true); |
452 } | 467 } |
453 | 468 |
454 void CallStackProfileMetricsProvider::OnRecordingDisabled() { | 469 void CallStackProfileMetricsProvider::OnRecordingDisabled() { |
455 PendingProfiles::GetInstance()->SetCollectionEnabled(false); | 470 PendingProfiles::GetInstance()->SetCollectionEnabled(false); |
456 } | 471 } |
457 | 472 |
458 void CallStackProfileMetricsProvider::ProvideGeneralMetrics( | 473 void CallStackProfileMetricsProvider::ProvideGeneralMetrics( |
459 ChromeUserMetricsExtension* uma_proto) { | 474 ChromeUserMetricsExtension* uma_proto) { |
460 std::vector<ProfilesState> pending_profiles; | 475 std::vector<ProfilesState> pending_profiles; |
461 PendingProfiles::GetInstance()->Swap(&pending_profiles); | 476 PendingProfiles::GetInstance()->Swap(&pending_profiles); |
462 | 477 |
463 DCHECK(IsReportingEnabledByFieldTrial() || pending_profiles.empty()); | 478 DCHECK(IsReportingEnabledByFieldTrial() || pending_profiles.empty()); |
464 | 479 |
465 for (const ProfilesState& profiles_state : pending_profiles) { | 480 for (const ProfilesState& profiles_state : pending_profiles) { |
466 for (const StackSamplingProfiler::CallStackProfile& profile : | 481 for (const StackSamplingProfiler::CallStackProfile& profile : |
467 profiles_state.profiles) { | 482 profiles_state.profiles) { |
468 SampledProfile* sampled_profile = uma_proto->add_sampled_profile(); | 483 SampledProfile* sampled_profile = uma_proto->add_sampled_profile(); |
469 sampled_profile->set_process(ToExecutionContextProcess( | 484 sampled_profile->set_process( |
470 profiles_state.params.process)); | 485 ToExecutionContextProcess(profiles_state.params.process)); |
471 sampled_profile->set_thread(ToExecutionContextThread( | 486 sampled_profile->set_thread( |
472 profiles_state.params.thread)); | 487 ToExecutionContextThread(profiles_state.params.thread)); |
473 sampled_profile->set_trigger_event(ToSampledProfileTriggerEvent( | 488 sampled_profile->set_trigger_event( |
474 profiles_state.params.trigger)); | 489 ToSampledProfileTriggerEvent(profiles_state.params.trigger)); |
475 CopyProfileToProto(profile, profiles_state.params.ordering_spec, | 490 CopyProfileToProto(profile, profiles_state.params.ordering_spec, |
476 sampled_profile->mutable_call_stack_profile()); | 491 sampled_profile->mutable_call_stack_profile()); |
477 } | 492 } |
478 } | 493 } |
479 } | 494 } |
480 | 495 |
481 // static | 496 // static |
482 void CallStackProfileMetricsProvider::ResetStaticStateForTesting() { | 497 void CallStackProfileMetricsProvider::ResetStaticStateForTesting() { |
483 PendingProfiles::GetInstance()->ResetToDefaultStateForTesting(); | 498 PendingProfiles::GetInstance()->ResetToDefaultStateForTesting(); |
484 } | 499 } |
485 | 500 |
486 // static | 501 // static |
487 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() { | 502 bool CallStackProfileMetricsProvider::IsReportingEnabledByFieldTrial() { |
488 const std::string group_name = base::FieldTrialList::FindFullName( | 503 return base::FeatureList::IsEnabled(kEnableReporting); |
489 CallStackProfileMetricsProvider::kFieldTrialName); | |
490 return group_name == | |
491 CallStackProfileMetricsProvider::kReportProfilesGroupName; | |
492 } | 504 } |
493 | 505 |
494 } // namespace metrics | 506 } // namespace metrics |
OLD | NEW |