diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 15:28:34 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:54:51 +0000 |
commit | 2a19c63448c84c1805fb1a585c3651318bb86ca7 (patch) | |
tree | eb17888e8531aa6ee5e85721bd553b832a7e5156 /chromium/components/metrics | |
parent | b014812705fc80bff0a5c120dfcef88f349816dc (diff) | |
download | qtwebengine-chromium-2a19c63448c84c1805fb1a585c3651318bb86ca7.tar.gz |
BASELINE: Update Chromium to 69.0.3497.70
Change-Id: I2b7b56e4e7a8b26656930def0d4575dc32b900a0
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/metrics')
31 files changed, 814 insertions, 641 deletions
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn index 75d36a28d49..15b3a14d569 100644 --- a/chromium/components/metrics/BUILD.gn +++ b/chromium/components/metrics/BUILD.gn @@ -105,7 +105,7 @@ static_library("metrics") { ] public_deps = [ - ":call_stack_profile_params", + ":call_stack_profile", "//third_party/metrics_proto", ] @@ -256,8 +256,10 @@ static_library("single_sample_metrics") { ] } -source_set("call_stack_profile_params") { +source_set("call_stack_profile") { sources = [ + "call_stack_profile_builder.cc", + "call_stack_profile_builder.h", "call_stack_profile_params.h", ] @@ -283,6 +285,7 @@ source_set("child_call_stacks") { "child_call_stack_profile_collector.h", ] deps = [ + ":call_stack_profile", "//components/metrics/public/interfaces:call_stack_mojo_bindings", "//services/service_manager/public/cpp", ] @@ -326,6 +329,7 @@ if (is_linux) { source_set("unit_tests") { testonly = true sources = [ + "call_stack_profile_builder_unittest.cc", "call_stack_profile_metrics_provider_unittest.cc", "child_call_stack_profile_collector_unittest.cc", "cloned_install_detector_unittest.cc", @@ -357,7 +361,7 @@ source_set("unit_tests") { ] deps = [ - ":call_stack_profile_params", + ":call_stack_profile", ":child_call_stacks", ":component_metrics", ":metrics", diff --git a/chromium/components/metrics/call_stack_profile_builder.cc b/chromium/components/metrics/call_stack_profile_builder.cc new file mode 100644 index 00000000000..f308c93da51 --- /dev/null +++ b/chromium/components/metrics/call_stack_profile_builder.cc @@ -0,0 +1,106 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/metrics/call_stack_profile_builder.h" + +#include <utility> + +#include "base/atomicops.h" +#include "base/logging.h" + +using StackSamplingProfiler = base::StackSamplingProfiler; + +namespace metrics { + +namespace { + +// This global variables holds the current system state and is recorded with +// every captured sample, done on a separate thread which is why updates to +// this must be atomic. A PostTask to move the the updates to that thread +// would skew the timing and a lock could result in deadlock if the thread +// making a change was also being profiled and got stopped. +static base::subtle::Atomic32 g_process_milestones = 0; + +void ChangeAtomicFlags(base::subtle::Atomic32* flags, + base::subtle::Atomic32 set, + base::subtle::Atomic32 clear) { + DCHECK(set != 0 || clear != 0); + DCHECK_EQ(0, set & clear); + + base::subtle::Atomic32 bits = base::subtle::NoBarrier_Load(flags); + while (true) { + base::subtle::Atomic32 existing = base::subtle::NoBarrier_CompareAndSwap( + flags, bits, (bits | set) & ~clear); + if (existing == bits) + break; + bits = existing; + } +} + +} // namespace + +CallStackProfileBuilder::CallStackProfileBuilder( + const CompletedCallback& callback) + : callback_(callback) {} + +CallStackProfileBuilder::~CallStackProfileBuilder() = default; + +void CallStackProfileBuilder::RecordAnnotations() { + // The code inside this method must not do anything that could acquire a + // mutex, including allocating memory (which includes LOG messages) because + // that mutex could be held by a stopped thread, thus resulting in deadlock. + sample_.process_milestones = + base::subtle::NoBarrier_Load(&g_process_milestones); +} + +void CallStackProfileBuilder::OnSampleCompleted( + std::vector<StackSamplingProfiler::InternalFrame> internal_frames) { + DCHECK(sample_.frames.empty()); + + // Dedup modules and convert InternalFrames to Frames. + for (const auto& internal_frame : internal_frames) { + const StackSamplingProfiler::InternalModule& module( + internal_frame.internal_module); + if (!module.is_valid) { + sample_.frames.emplace_back(internal_frame.instruction_pointer, + base::kUnknownModuleIndex); + continue; + } + + auto loc = module_index_.find(module.base_address); + if (loc == module_index_.end()) { + profile_.modules.emplace_back(module.base_address, module.id, + module.filename); + size_t index = profile_.modules.size() - 1; + loc = module_index_.insert(std::make_pair(module.base_address, index)) + .first; + } + sample_.frames.emplace_back(internal_frame.instruction_pointer, + loc->second); + } + + profile_.samples.push_back(std::move(sample_)); + sample_ = StackSamplingProfiler::Sample(); +} + +void CallStackProfileBuilder::OnProfileCompleted( + base::TimeDelta profile_duration, + base::TimeDelta sampling_period) { + profile_.profile_duration = profile_duration; + profile_.sampling_period = sampling_period; + + // Run the associated callback, passing the collected profile. + callback_.Run(std::move(profile_)); +} + +// static +void CallStackProfileBuilder::SetProcessMilestone(int milestone) { + DCHECK_LE(0, milestone); + DCHECK_GT(static_cast<int>(sizeof(g_process_milestones) * 8), milestone); + DCHECK_EQ(0, base::subtle::NoBarrier_Load(&g_process_milestones) & + (1 << milestone)); + ChangeAtomicFlags(&g_process_milestones, 1 << milestone, 0); +} + +} // namespace metrics diff --git a/chromium/components/metrics/call_stack_profile_builder.h b/chromium/components/metrics/call_stack_profile_builder.h new file mode 100644 index 00000000000..ec01592686b --- /dev/null +++ b/chromium/components/metrics/call_stack_profile_builder.h @@ -0,0 +1,77 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_METRICS_CALL_STACK_PROFILE_BUILDER_H_ +#define COMPONENTS_METRICS_CALL_STACK_PROFILE_BUILDER_H_ + +#include "base/profiler/stack_sampling_profiler.h" + +#include <map> + +#include "base/callback.h" + +namespace metrics { + +// CallStackProfileBuilder builds a CallStackProfile from the collected sampling +// data. +// +// The results of the profile building -- a CallStackProfile, is passed to the +// completed callback. A CallStackProfile contains a set of Samples and +// Modules, and other sampling information. One Sample corresponds to a single +// recorded stack, and the Modules record those modules associated with the +// recorded stack frames. +class CallStackProfileBuilder + : public base::StackSamplingProfiler::ProfileBuilder { + public: + // The callback type used to collect a completed profile. The passed + // CallStackProfile is move-only. Other threads, including the UI thread, may + // block on callback completion so this should run as quickly as possible. + // + // IMPORTANT NOTE: The callback is invoked on a thread the profiler + // constructs, rather than on the thread used to construct the profiler, and + // thus the callback must be callable on any thread. For threads with message + // loops that create CallStackProfileBuilders, posting a task to the message + // loop with the moved (i.e. std::move) profile is the thread-safe callback + // implementation. + using CompletedCallback = + base::Callback<void(base::StackSamplingProfiler::CallStackProfile)>; + + CallStackProfileBuilder(const CompletedCallback& callback); + + ~CallStackProfileBuilder() override; + + // base::StackSamplingProfiler::ProfileBuilder: + void RecordAnnotations() override; + void OnSampleCompleted(std::vector<base::StackSamplingProfiler::InternalFrame> + internal_frames) override; + void OnProfileCompleted(base::TimeDelta profile_duration, + base::TimeDelta sampling_period) override; + + // Sets the current system state that is recorded with each captured stack + // frame. This is thread-safe so can be called from anywhere. The parameter + // value should be from an enumeration of the appropriate type with values + // ranging from 0 to 31, inclusive. This sets bits within Sample field of + // |process_milestones|. The actual meanings of these bits are defined + // (globally) by the caller(s). + static void SetProcessMilestone(int milestone); + + private: + // The collected stack samples. + base::StackSamplingProfiler::CallStackProfile profile_; + + // The current sample being recorded. + base::StackSamplingProfiler::Sample sample_; + + // The indexes of internal modules, indexed by module's base_address. + std::map<uintptr_t, size_t> module_index_; + + // Callback made when sampling a profile completes. + const CompletedCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(CallStackProfileBuilder); +}; + +} // namespace metrics + +#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_BUILDER_H_ diff --git a/chromium/components/metrics/call_stack_profile_builder_unittest.cc b/chromium/components/metrics/call_stack_profile_builder_unittest.cc new file mode 100644 index 00000000000..93ff7cccca9 --- /dev/null +++ b/chromium/components/metrics/call_stack_profile_builder_unittest.cc @@ -0,0 +1,159 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/metrics/call_stack_profile_builder.h" + +#include "base/files/file_path.h" +#include "base/test/bind_test_util.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +using StackSamplingProfiler = base::StackSamplingProfiler; +using InternalFrame = StackSamplingProfiler::InternalFrame; +using InternalModule = StackSamplingProfiler::InternalModule; +using CallStackProfile = StackSamplingProfiler::CallStackProfile; + +namespace metrics { + +namespace { + +// Called on the profiler thread when complete, to collect profile. +void SaveProfile(CallStackProfile* profile, CallStackProfile pending_profile) { + *profile = std::move(pending_profile); +} + +} // namespace + +TEST(CallStackProfileBuilderTest, SetProcessMilestone) { + CallStackProfile profile; + + // Set up a callback to record the CallStackProfile to local variable + // |profile|. + auto profile_builder = std::make_unique<CallStackProfileBuilder>( + Bind(&SaveProfile, Unretained(&profile))); + + profile_builder->RecordAnnotations(); + profile_builder->OnSampleCompleted(std::vector<InternalFrame>()); + + CallStackProfileBuilder::SetProcessMilestone(1); + profile_builder->RecordAnnotations(); + profile_builder->OnSampleCompleted(std::vector<InternalFrame>()); + + profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta()); + + ASSERT_EQ(2u, profile.samples.size()); + EXPECT_EQ(0u, profile.samples[0].process_milestones); + EXPECT_EQ(1u << 1, profile.samples[1].process_milestones); +} + +TEST(CallStackProfileBuilderTest, OnSampleCompleted) { + CallStackProfile profile; + + // Set up a callback to record the CallStackProfile to local variable + // |profile|. + auto profile_builder = std::make_unique<CallStackProfileBuilder>( + Bind(&SaveProfile, Unretained(&profile))); + + InternalModule module1 = {0xccccdddd, "1", + base::FilePath(FILE_PATH_LITERAL("file_path_1"))}; + InternalModule module2 = {0xccddccdd, "2", + base::FilePath(FILE_PATH_LITERAL("file_path_2"))}; + InternalFrame frame1 = {0xaaaabbbb, module1}; + InternalFrame frame2 = {0xaabbaabb, module2}; + + std::vector<InternalFrame> frames = {frame1, frame2}; + + profile_builder->OnSampleCompleted(frames); + profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta()); + + ASSERT_EQ(1u, profile.samples.size()); + ASSERT_EQ(2u, profile.samples[0].frames.size()); + EXPECT_EQ(0u, profile.samples[0].frames[0].module_index); + EXPECT_EQ(1u, profile.samples[0].frames[1].module_index); +} + +TEST(CallStackProfileBuilderTest, OnProfileCompleted) { + CallStackProfile profile; + + // Set up a callback to record the CallStackProfile to local variable + // |profile|. + auto profile_builder = std::make_unique<CallStackProfileBuilder>( + Bind(&SaveProfile, Unretained(&profile))); + + InternalModule module1 = {0xccccdddd, "1", + base::FilePath(FILE_PATH_LITERAL("file_path_1"))}; + InternalModule module2 = {0xccddccdd, "2", + base::FilePath(FILE_PATH_LITERAL("file_path_2"))}; + InternalFrame frame1 = {0xaaaabbbb, module1}; + InternalFrame frame2 = {0xaabbaabb, module2}; + + std::vector<InternalFrame> frames = {frame1, frame2}; + + profile_builder->OnSampleCompleted(frames); + profile_builder->OnProfileCompleted(base::TimeDelta::FromMilliseconds(500), + base::TimeDelta::FromMilliseconds(100)); + + ASSERT_EQ(1u, profile.samples.size()); + ASSERT_EQ(2u, profile.samples[0].frames.size()); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), profile.profile_duration); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(100), profile.sampling_period); +} + +TEST(CallStackProfileBuilderTest, InvalidModule) { + CallStackProfile profile; + + // Set up a callback to record the CallStackProfile to local variable + // |profile|. + auto profile_builder = std::make_unique<CallStackProfileBuilder>( + Bind(&SaveProfile, Unretained(&profile))); + + InternalModule module1; + InternalModule module2 = {0xccddccdd, "2", + base::FilePath(FILE_PATH_LITERAL("file_path_2"))}; + InternalFrame frame1 = {0xaaaabbbb, module1}; + InternalFrame frame2 = {0xaabbaabb, module2}; + + std::vector<InternalFrame> frames = {frame1, frame2}; + + profile_builder->OnSampleCompleted(frames); + profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta()); + + ASSERT_EQ(1u, profile.samples.size()); + ASSERT_EQ(2u, profile.samples[0].frames.size()); + + // module1 has no information hence invalid. The module index of the frame is + // therefore base::kUnknownModuleIndex. + EXPECT_EQ(base::kUnknownModuleIndex, + profile.samples[0].frames[0].module_index); + + EXPECT_EQ(0u, profile.samples[0].frames[1].module_index); +} + +TEST(CallStackProfileBuilderTest, DedupModules) { + CallStackProfile profile; + auto profile_builder = std::make_unique<CallStackProfileBuilder>( + Bind(&SaveProfile, Unretained(&profile))); + + InternalModule module1 = {0xccccdddd, "1", + base::FilePath(FILE_PATH_LITERAL("file_path_1"))}; + InternalModule module2 = {0xccccdddd, "2", + base::FilePath(FILE_PATH_LITERAL("file_path_2"))}; + InternalFrame frame1 = {0xaaaabbbb, module1}; + InternalFrame frame2 = {0xaabbaabb, module2}; + + std::vector<InternalFrame> frames = {frame1, frame2}; + + profile_builder->OnSampleCompleted(frames); + profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta()); + + ASSERT_EQ(1u, profile.samples.size()); + ASSERT_EQ(2u, profile.samples[0].frames.size()); + + // Since module1 and module2 have the same base address 0xccccdddd, they are + // considered the same module and therefore deduped. + EXPECT_EQ(0u, profile.samples[0].frames[0].module_index); + EXPECT_EQ(0u, profile.samples[0].frames[1].module_index); +} + +} // namespace metrics diff --git a/chromium/components/metrics/call_stack_profile_collector.cc b/chromium/components/metrics/call_stack_profile_collector.cc index aa127fbf737..dc16a0fc909 100644 --- a/chromium/components/metrics/call_stack_profile_collector.cc +++ b/chromium/components/metrics/call_stack_profile_collector.cc @@ -5,7 +5,6 @@ #include "components/metrics/call_stack_profile_collector.h" #include <utility> -#include <vector> #include <memory> @@ -30,16 +29,15 @@ void CallStackProfileCollector::Create( std::move(request)); } -void CallStackProfileCollector::Collect( - const CallStackProfileParams& params, - base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles) { +void CallStackProfileCollector::Collect(const CallStackProfileParams& params, + base::TimeTicks start_timestamp, + CallStackProfile profile) { if (params.process != expected_process_) return; CallStackProfileParams params_copy = params; - CallStackProfileMetricsProvider::ReceiveCompletedProfiles( - params_copy, start_timestamp, std::move(profiles)); + CallStackProfileMetricsProvider::ReceiveCompletedProfile( + params_copy, start_timestamp, std::move(profile)); } } // namespace metrics diff --git a/chromium/components/metrics/call_stack_profile_collector.h b/chromium/components/metrics/call_stack_profile_collector.h index 6eeb6a87b44..97a4db4ca56 100644 --- a/chromium/components/metrics/call_stack_profile_collector.h +++ b/chromium/components/metrics/call_stack_profile_collector.h @@ -25,7 +25,7 @@ class CallStackProfileCollector : public mojom::CallStackProfileCollector { // mojom::CallStackProfileCollector: void Collect(const CallStackProfileParams& params, base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles) override; + CallStackProfile profile) override; private: // Profile params are validated to come from this process. Profiles with a diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.cc b/chromium/components/metrics/call_stack_profile_metrics_provider.cc index bce2bbbb871..9672bbaeb50 100644 --- a/chromium/components/metrics/call_stack_profile_metrics_provider.cc +++ b/chromium/components/metrics/call_stack_profile_metrics_provider.cc @@ -24,6 +24,7 @@ #include "base/process/process_info.h" #include "base/profiler/stack_sampling_profiler.h" #include "base/single_thread_task_runner.h" +#include "base/stl_util.h" #include "base/synchronization/lock.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -36,6 +37,14 @@ namespace metrics { namespace { +// Cap the number of pending profiles to avoid excessive memory usage when +// profile uploads are delayed (e.g. due to being offline). 1250 profiles +// corresponds to 80MB of storage. Capping at this threshold loses approximately +// 0.5% of profiles on canary and dev. +// TODO(chengx): Remove this threshold after moving to a more memory-efficient +// profile representation. +const size_t kMaxPendingProfiles = 1250; + // Provide a mapping from the C++ "enum" definition of various process mile- // stones to the equivalent protobuf "enum" definition. This table-lookup // conversion allows for the implementation to evolve and still be compatible @@ -52,16 +61,16 @@ const ProcessPhase ProcessPhase::SHUTDOWN_START, }; -// ProfilesState -------------------------------------------------------------- +// ProfileState -------------------------------------------------------------- // A set of profiles and the CallStackProfileMetricsProvider state associated // with them. -struct ProfilesState { - ProfilesState(const CallStackProfileParams& params, - base::TimeTicks start_timestamp, - StackSamplingProfiler::CallStackProfiles profiles); - ProfilesState(ProfilesState&&); - ProfilesState& operator=(ProfilesState&&); +struct ProfileState { + ProfileState(const CallStackProfileParams& params, + base::TimeTicks start_timestamp, + StackSamplingProfiler::CallStackProfile profile); + ProfileState(ProfileState&&); + ProfileState& operator=(ProfileState&&); // The metrics-related parameters provided to // CallStackProfileMetricsProvider::GetProfilerCallback(). @@ -70,24 +79,24 @@ struct ProfilesState { // The time at which the profile collection was started. base::TimeTicks start_timestamp; - // The call stack profiles collected by the profiler. - StackSamplingProfiler::CallStackProfiles profiles; + // The call stack profile collected by the profiler. + StackSamplingProfiler::CallStackProfile profile; private: - DISALLOW_COPY_AND_ASSIGN(ProfilesState); + DISALLOW_COPY_AND_ASSIGN(ProfileState); }; -ProfilesState::ProfilesState(const CallStackProfileParams& params, - base::TimeTicks start_timestamp, - StackSamplingProfiler::CallStackProfiles profiles) +ProfileState::ProfileState(const CallStackProfileParams& params, + base::TimeTicks start_timestamp, + StackSamplingProfiler::CallStackProfile profile) : params(params), start_timestamp(start_timestamp), - profiles(std::move(profiles)) {} + profile(std::move(profile)) {} -ProfilesState::ProfilesState(ProfilesState&&) = default; +ProfileState::ProfileState(ProfileState&&) = default; // Some versions of GCC need this for push_back to work with std::move. -ProfilesState& ProfilesState::operator=(ProfilesState&&) = default; +ProfileState& ProfileState::operator=(ProfileState&&) = default; // PendingProfiles ------------------------------------------------------------ @@ -103,7 +112,7 @@ class PendingProfiles { public: static PendingProfiles* GetInstance(); - void Swap(std::vector<ProfilesState>* profiles); + void Swap(std::vector<ProfileState>* profiles); // Enables the collection of profiles by CollectProfilesIfCollectionEnabled if // |enabled| is true. Otherwise, clears current profiles and ignores profiles @@ -113,9 +122,9 @@ class PendingProfiles { // True if profiles are being collected. bool IsCollectionEnabled() const; - // Adds |profiles| to the list of profiles if collection is enabled; it is + // Adds |profile| to the list of profiles if collection is enabled; it is // not const& because it must be passed with std::move. - void CollectProfilesIfCollectionEnabled(ProfilesState profiles); + void CollectProfilesIfCollectionEnabled(ProfileState profile); // Allows testing against the initial state multiple times. void ResetToDefaultStateForTesting(); @@ -124,7 +133,7 @@ class PendingProfiles { friend struct base::DefaultSingletonTraits<PendingProfiles>; PendingProfiles(); - ~PendingProfiles(); + ~PendingProfiles() = default; mutable base::Lock lock_; @@ -137,7 +146,7 @@ class PendingProfiles { base::TimeTicks last_collection_disable_time_; // The set of completed profiles that should be reported. - std::vector<ProfilesState> profiles_; + std::vector<ProfileState> profiles_; DISALLOW_COPY_AND_ASSIGN(PendingProfiles); }; @@ -149,7 +158,7 @@ PendingProfiles* PendingProfiles::GetInstance() { base::LeakySingletonTraits<PendingProfiles>>::get(); } -void PendingProfiles::Swap(std::vector<ProfilesState>* profiles) { +void PendingProfiles::Swap(std::vector<ProfileState>* profiles) { base::AutoLock scoped_lock(lock_); profiles_.swap(*profiles); } @@ -170,19 +179,19 @@ bool PendingProfiles::IsCollectionEnabled() const { return collection_enabled_; } -void PendingProfiles::CollectProfilesIfCollectionEnabled( - ProfilesState profiles) { +void PendingProfiles::CollectProfilesIfCollectionEnabled(ProfileState profile) { base::AutoLock scoped_lock(lock_); // Only collect if collection is not disabled and hasn't been disabled // since the start of collection for this profile. if (!collection_enabled_ || (!last_collection_disable_time_.is_null() && - last_collection_disable_time_ >= profiles.start_timestamp)) { + last_collection_disable_time_ >= profile.start_timestamp)) { return; } - profiles_.push_back(std::move(profiles)); + if (profiles_.size() < kMaxPendingProfiles) + profiles_.push_back(std::move(profile)); } void PendingProfiles::ResetToDefaultStateForTesting() { @@ -200,23 +209,20 @@ void PendingProfiles::ResetToDefaultStateForTesting() { // CallStackProfileMetricsProvider. PendingProfiles::PendingProfiles() : collection_enabled_(true) {} -PendingProfiles::~PendingProfiles() {} - -// Functions to process completed profiles ------------------------------------ +// Functions to process completed profile ------------------------------------ // Will be invoked on either the main thread or the profiler's thread. Provides -// the profiles to PendingProfiles to append, if the collecting state allows. -void ReceiveCompletedProfilesImpl( +// the profile to PendingProfiles to append, if the collecting state allows. +void ReceiveCompletedProfileImpl( const CallStackProfileParams& params, base::TimeTicks start_timestamp, - StackSamplingProfiler::CallStackProfiles profiles) { + StackSamplingProfiler::CallStackProfile profile) { PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled( - ProfilesState(params, start_timestamp, std::move(profiles))); + ProfileState(params, start_timestamp, std::move(profile))); } -// Invoked on an arbitrary thread. Ignores the provided profiles. -void IgnoreCompletedProfiles( - StackSamplingProfiler::CallStackProfiles profiles) {} +// Invoked on an arbitrary thread. Ignores the provided profile. +void IgnoreCompletedProfile(StackSamplingProfiler::CallStackProfile profile) {} // Functions to encode protobufs ---------------------------------------------- @@ -237,12 +243,12 @@ void CopySampleToProto( const StackSamplingProfiler::Sample& sample, const std::vector<StackSamplingProfiler::Module>& modules, CallStackProfile::Sample* proto_sample) { - for (const StackSamplingProfiler::Frame& frame : sample.frames) { + for (const auto& frame : sample.frames) { CallStackProfile::Entry* entry = proto_sample->add_entry(); // A frame may not have a valid module. If so, we can't compute the // instruction pointer offset, and we don't want to send bare pointers, so // leave call_stack_entry empty. - if (frame.module_index == StackSamplingProfiler::Frame::kUnknownModuleIndex) + if (frame.module_index == base::kUnknownModuleIndex) continue; int64_t module_offset = reinterpret_cast<const char*>(frame.instruction_pointer) - @@ -264,7 +270,7 @@ void CopyAnnotationsToProto(uint32_t new_milestones, ++bit) { const uint32_t flag = 1U << bit; if (new_milestones & flag) { - if (bit >= arraysize(kProtoPhases)) { + if (bit >= base::size(kProtoPhases)) { NOTREACHED(); continue; } @@ -283,7 +289,7 @@ void CopyProfileToProto( return; const bool preserve_order = - (ordering_spec == CallStackProfileParams::PRESERVE_ORDER); + ordering_spec == CallStackProfileParams::PRESERVE_ORDER; std::map<StackSamplingProfiler::Sample, int> sample_index; uint32_t milestones = 0; @@ -319,7 +325,7 @@ void CopyProfileToProto( } } - for (const StackSamplingProfiler::Module& module : profile.modules) { + for (const auto& module : profile.modules) { CallStackProfile::ModuleIdentifier* module_id = proto_profile->add_module_id(); module_id->set_build_id(module.id); @@ -366,7 +372,7 @@ Thread ToExecutionContextThread(CallStackProfileParams::Thread thread) { case CallStackProfileParams::UNKNOWN_THREAD: return UNKNOWN_THREAD; case CallStackProfileParams::MAIN_THREAD: - return UI_THREAD; + return MAIN_THREAD; case CallStackProfileParams::IO_THREAD: return IO_THREAD; case CallStackProfileParams::COMPOSITOR_THREAD: @@ -403,31 +409,29 @@ SampledProfile::TriggerEvent ToSampledProfileTriggerEvent( const base::Feature CallStackProfileMetricsProvider::kEnableReporting = { "SamplingProfilerReporting", base::FEATURE_DISABLED_BY_DEFAULT}; -CallStackProfileMetricsProvider::CallStackProfileMetricsProvider() { -} +CallStackProfileMetricsProvider::CallStackProfileMetricsProvider() {} -CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() { -} +CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {} -StackSamplingProfiler::CompletedCallback +CallStackProfileBuilder::CompletedCallback CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess( const CallStackProfileParams& params) { - // Ignore the profiles if the collection is disabled. If the collection state + // Ignore the profile if the collection is disabled. If the collection state // changes while collecting, this will be detected by the callback and - // profiles will be ignored at that point. + // profile will be ignored at that point. if (!PendingProfiles::GetInstance()->IsCollectionEnabled()) - return base::Bind(&IgnoreCompletedProfiles); + return base::Bind(&IgnoreCompletedProfile); - return base::Bind(&ReceiveCompletedProfilesImpl, params, + return base::Bind(&ReceiveCompletedProfileImpl, params, base::TimeTicks::Now()); } // static -void CallStackProfileMetricsProvider::ReceiveCompletedProfiles( +void CallStackProfileMetricsProvider::ReceiveCompletedProfile( const CallStackProfileParams& params, base::TimeTicks profile_start_time, - base::StackSamplingProfiler::CallStackProfiles profiles) { - ReceiveCompletedProfilesImpl(params, profile_start_time, std::move(profiles)); + StackSamplingProfiler::CallStackProfile profile) { + ReceiveCompletedProfileImpl(params, profile_start_time, std::move(profile)); } void CallStackProfileMetricsProvider::OnRecordingEnabled() { @@ -441,25 +445,23 @@ void CallStackProfileMetricsProvider::OnRecordingDisabled() { void CallStackProfileMetricsProvider::ProvideCurrentSessionData( ChromeUserMetricsExtension* uma_proto) { - std::vector<ProfilesState> pending_profiles; + std::vector<ProfileState> pending_profiles; PendingProfiles::GetInstance()->Swap(&pending_profiles); DCHECK(base::FeatureList::IsEnabled(kEnableReporting) || pending_profiles.empty()); - for (const ProfilesState& profiles_state : pending_profiles) { - for (const StackSamplingProfiler::CallStackProfile& profile : - profiles_state.profiles) { - SampledProfile* sampled_profile = uma_proto->add_sampled_profile(); - sampled_profile->set_process( - ToExecutionContextProcess(profiles_state.params.process)); - sampled_profile->set_thread( - ToExecutionContextThread(profiles_state.params.thread)); - sampled_profile->set_trigger_event( - ToSampledProfileTriggerEvent(profiles_state.params.trigger)); - CopyProfileToProto(profile, profiles_state.params.ordering_spec, - sampled_profile->mutable_call_stack_profile()); - } + for (const auto& profile_state : pending_profiles) { + SampledProfile* sampled_profile = uma_proto->add_sampled_profile(); + sampled_profile->set_process( + ToExecutionContextProcess(profile_state.params.process)); + sampled_profile->set_thread( + ToExecutionContextThread(profile_state.params.thread)); + sampled_profile->set_trigger_event( + ToSampledProfileTriggerEvent(profile_state.params.trigger)); + CopyProfileToProto(profile_state.profile, + profile_state.params.ordering_spec, + sampled_profile->mutable_call_stack_profile()); } } diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.h b/chromium/components/metrics/call_stack_profile_metrics_provider.h index f995a9a411b..4b05c4e896d 100644 --- a/chromium/components/metrics/call_stack_profile_metrics_provider.h +++ b/chromium/components/metrics/call_stack_profile_metrics_provider.h @@ -5,12 +5,11 @@ #ifndef COMPONENTS_METRICS_CALL_STACK_PROFILE_METRICS_PROVIDER_H_ #define COMPONENTS_METRICS_CALL_STACK_PROFILE_METRICS_PROVIDER_H_ -#include <vector> - #include "base/feature_list.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/profiler/stack_sampling_profiler.h" +#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_params.h" #include "components/metrics/metrics_provider.h" @@ -22,8 +21,9 @@ class ChromeUserMetricsExtension; class CallStackProfileMetricsProvider : public MetricsProvider { public: // These milestones of a process lifetime can be passed as process "mile- - // stones" to StackSmaplingProfile::SetProcessMilestone(). Be sure to update - // the translation constants at the top of the .cc file when this is changed. + // stones" to CallStackProfileBuilder::SetProcessMilestone(). Be sure to + // update the translation constants at the top of the .cc file when this is + // changed. enum Milestones : int { MAIN_LOOP_START, MAIN_NAVIGATION_START, @@ -38,20 +38,21 @@ class CallStackProfileMetricsProvider : public MetricsProvider { CallStackProfileMetricsProvider(); ~CallStackProfileMetricsProvider() override; - // Returns a callback for use with StackSamplingProfiler that sets up + // Returns a callback for use with CallStackProfileBuilder that sets up // parameters for general browser process sampling. The callback should be - // immediately passed to the StackSamplingProfiler, and should not be reused. - static base::StackSamplingProfiler::CompletedCallback + // immediately passed to the CallStackProfileBuilder, and should not be + // reused. + static CallStackProfileBuilder::CompletedCallback GetProfilerCallbackForBrowserProcess(const CallStackProfileParams& params); - // Provides completed stack profiles to the metrics provider. Intended for use + // Provides completed stack profile to the metrics provider. Intended for use // when receiving profiles over IPC. In-process StackSamplingProfiler users - // should instead use a variant of GetProfilerCallback*(). |profiles| is not + // should instead use a variant of GetProfilerCallback*(). |profile| is not // const& because it must be passed with std::move. - static void ReceiveCompletedProfiles( + static void ReceiveCompletedProfile( const CallStackProfileParams& params, base::TimeTicks profile_start_time, - base::StackSamplingProfiler::CallStackProfiles profiles); + base::StackSamplingProfiler::CallStackProfile profile); // MetricsProvider: void OnRecordingEnabled() override; diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc index c4777110ef4..309235c3732 100644 --- a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc +++ b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/profiler/stack_sampling_profiler.h" #include "base/run_loop.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" @@ -23,9 +24,8 @@ using base::StackSamplingProfiler; using Frame = StackSamplingProfiler::Frame; using Module = StackSamplingProfiler::Module; -using Profile = StackSamplingProfiler::CallStackProfile; -using Profiles = StackSamplingProfiler::CallStackProfiles; using Sample = StackSamplingProfiler::Sample; +using Profile = StackSamplingProfiler::CallStackProfile; namespace { @@ -56,61 +56,55 @@ struct ExpectedProtoProfile { int sample_count; }; -class ProfilesFactory { +class ProfileFactory { public: - ProfilesFactory() {} - ~ProfilesFactory() {} + ProfileFactory(int duration_ms, int interval_ms) { + profile_.profile_duration = base::TimeDelta::FromMilliseconds(duration_ms); + profile_.sampling_period = base::TimeDelta::FromMilliseconds(interval_ms); + } + ~ProfileFactory() {} - ProfilesFactory& AddMilestone(int milestone); - ProfilesFactory& NewProfile(int duration_ms, int interval_ms); - ProfilesFactory& NewSample(); - ProfilesFactory& AddFrame(size_t module, uintptr_t offset); - ProfilesFactory& DefineModule(const char* name, - const base::FilePath& path, - uintptr_t base); + ProfileFactory& AddMilestone(int milestone); + ProfileFactory& NewSample(); + ProfileFactory& AddFrame(size_t module, uintptr_t offset); + ProfileFactory& DefineModule(const char* name, + const base::FilePath& path, + uintptr_t base); - Profiles Build(); + Profile Build(); private: - Profiles profiles_; + Profile profile_; uint32_t process_milestones_ = 0; - DISALLOW_COPY_AND_ASSIGN(ProfilesFactory); + DISALLOW_COPY_AND_ASSIGN(ProfileFactory); }; -ProfilesFactory& ProfilesFactory::AddMilestone(int milestone) { +ProfileFactory& ProfileFactory::AddMilestone(int milestone) { process_milestones_ |= 1 << milestone; return *this; } -ProfilesFactory& ProfilesFactory::NewProfile(int duration_ms, int interval_ms) { - profiles_.push_back(Profile()); - Profile* profile = &profiles_.back(); - profile->profile_duration = base::TimeDelta::FromMilliseconds(duration_ms); - profile->sampling_period = base::TimeDelta::FromMilliseconds(interval_ms); +ProfileFactory& ProfileFactory::NewSample() { + profile_.samples.push_back(Sample()); + profile_.samples.back().process_milestones = process_milestones_; return *this; } -ProfilesFactory& ProfilesFactory::NewSample() { - profiles_.back().samples.push_back(Sample()); - profiles_.back().samples.back().process_milestones = process_milestones_; +ProfileFactory& ProfileFactory::AddFrame(size_t module, uintptr_t offset) { + profile_.samples.back().frames.push_back(Frame(offset, module)); return *this; } -ProfilesFactory& ProfilesFactory::AddFrame(size_t module, uintptr_t offset) { - profiles_.back().samples.back().frames.push_back(Frame(offset, module)); +ProfileFactory& ProfileFactory::DefineModule(const char* name, + const base::FilePath& path, + uintptr_t base) { + profile_.modules.push_back(Module(base, name, path)); return *this; } -ProfilesFactory& ProfilesFactory::DefineModule(const char* name, - const base::FilePath& path, - uintptr_t base) { - profiles_.back().modules.push_back(Module(base, name, path)); - return *this; -} - -Profiles ProfilesFactory::Build() { - return std::move(profiles_); +Profile ProfileFactory::Build() { + return std::move(profile_); } } // namespace @@ -118,7 +112,7 @@ Profiles ProfilesFactory::Build() { namespace metrics { // This test fixture enables the feature that -// CallStackProfileMetricsProvider depends on to report profiles. +// CallStackProfileMetricsProvider depends on to report a profile. class CallStackProfileMetricsProviderTest : public testing::Test { public: CallStackProfileMetricsProviderTest() { @@ -128,11 +122,11 @@ class CallStackProfileMetricsProviderTest : public testing::Test { ~CallStackProfileMetricsProviderTest() override {} - // Utility function to append profiles to the metrics provider. - void AppendProfiles(const CallStackProfileParams& params, Profiles profiles) { + // Utility function to append a profile to the metrics provider. + void AppendProfile(const CallStackProfileParams& params, Profile profile) { CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess( params) - .Run(std::move(profiles)); + .Run(std::move(profile)); } void VerifyProfileProto(const ExpectedProtoProfile& expected, @@ -203,160 +197,6 @@ void CallStackProfileMetricsProviderTest::VerifyProfileProto( } } -// Checks that all properties from multiple profiles are filled as expected. -TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) { - const uintptr_t moduleA_base_address = 0x1000; - const uintptr_t moduleB_base_address = 0x2000; - const uintptr_t moduleC_base_address = 0x3000; - const char* moduleA_name = "ABCD"; - const char* moduleB_name = "EFGH"; - const char* moduleC_name = "MNOP"; - - // Values for Windows generated with: - // perl -MDigest::MD5=md5 -MEncode=encode - // -e 'for(@ARGV){printf "%x\n", unpack "Q>", md5 encode "UTF-16LE", $_}' - // chrome.exe third_party.dll third_party2.dll - // - // Values for Linux generated with: - // perl -MDigest::MD5=md5 - // -e 'for(@ARGV){printf "%x\n", unpack "Q>", md5 $_}' - // chrome third_party.so third_party2.so -#if defined(OS_WIN) - uint64_t moduleA_md5 = 0x46C3E4166659AC02ULL; - uint64_t moduleB_md5 = 0x7E2B8BFDDEAE1ABAULL; - uint64_t moduleC_md5 = 0x87B66F4573A4D5CAULL; - base::FilePath moduleA_path(L"c:\\some\\path\\to\\chrome.exe"); - base::FilePath moduleB_path(L"c:\\some\\path\\to\\third_party.dll"); - base::FilePath moduleC_path(L"c:\\some\\path\\to\\third_party2.dll"); -#else - uint64_t moduleA_md5 = 0x554838A8451AC36CULL; - uint64_t moduleB_md5 = 0x843661148659C9F8ULL; - uint64_t moduleC_md5 = 0xB4647E539FA6EC9EULL; - base::FilePath moduleA_path("/some/path/to/chrome"); - base::FilePath moduleB_path("/some/path/to/third_party.so"); - base::FilePath moduleC_path("/some/path/to/third_party2.so"); -#endif - - // Represents two stack samples for each of two profiles, where each stack - // contains three frames. Each frame contains an instruction pointer and a - // module index corresponding to the module for the profile in - // profile_modules. - // - // So, the first stack sample below has its top frame in module 0 at an offset - // of 0x10 from the module's base address, the next-to-top frame in module 1 - // at an offset of 0x20 from the module's base address, and the bottom frame - // in module 0 at an offset of 0x30 from the module's base address - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .DefineModule(moduleA_name, moduleA_path, moduleA_base_address) - .DefineModule(moduleB_name, moduleB_path, moduleB_base_address) - - .NewSample() - .AddFrame(0, moduleA_base_address + 0x10) - .AddFrame(1, moduleB_base_address + 0x20) - .AddFrame(0, moduleA_base_address + 0x30) - .NewSample() - .AddFrame(1, moduleB_base_address + 0x10) - .AddFrame(0, moduleA_base_address + 0x20) - .AddFrame(1, moduleB_base_address + 0x30) - - .NewProfile(200, 20) - .DefineModule(moduleC_name, moduleC_path, moduleC_base_address) - .DefineModule(moduleA_name, moduleA_path, moduleA_base_address) - - .NewSample() - .AddFrame(0, moduleC_base_address + 0x10) - .AddFrame(1, moduleA_base_address + 0x20) - .AddFrame(0, moduleC_base_address + 0x30) - .NewSample() - .AddFrame(1, moduleA_base_address + 0x10) - .AddFrame(0, moduleC_base_address + 0x20) - .AddFrame(1, moduleA_base_address + 0x30) - - .Build(); - - const ExpectedProtoModule expected_proto_modules1[] = { - { moduleA_name, moduleA_md5, moduleA_base_address }, - { moduleB_name, moduleB_md5, moduleB_base_address } - }; - - const ExpectedProtoEntry expected_proto_entries11[] = { - { 0, 0x10 }, - { 1, 0x20 }, - { 0, 0x30 }, - }; - const ExpectedProtoEntry expected_proto_entries12[] = { - { 1, 0x10 }, - { 0, 0x20 }, - { 1, 0x30 }, - }; - const ExpectedProtoSample expected_proto_samples1[] = { - { - 0, expected_proto_entries11, arraysize(expected_proto_entries11), 1, - }, - { - 0, expected_proto_entries12, arraysize(expected_proto_entries12), 1, - }, - }; - - const ExpectedProtoModule expected_proto_modules2[] = { - { moduleC_name, moduleC_md5, moduleC_base_address }, - { moduleA_name, moduleA_md5, moduleA_base_address } - }; - - const ExpectedProtoEntry expected_proto_entries21[] = { - { 0, 0x10 }, - { 1, 0x20 }, - { 0, 0x30 }, - }; - const ExpectedProtoEntry expected_proto_entries22[] = { - { 1, 0x10 }, - { 0, 0x20 }, - { 1, 0x30 }, - }; - const ExpectedProtoSample expected_proto_samples2[] = { - { - 0, expected_proto_entries11, arraysize(expected_proto_entries21), 1, - }, - { - 0, expected_proto_entries12, arraysize(expected_proto_entries22), 1, - }, - }; - - const ExpectedProtoProfile expected_proto_profiles[] = { - { - 100, 10, - expected_proto_modules1, arraysize(expected_proto_modules1), - expected_proto_samples1, arraysize(expected_proto_samples1), - }, - { - 200, 20, - expected_proto_modules2, arraysize(expected_proto_modules2), - expected_proto_samples2, arraysize(expected_proto_samples2), - }, - }; - - ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size()); - - CallStackProfileMetricsProvider provider; - provider.OnRecordingEnabled(); - CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, - CallStackProfileParams::MAIN_THREAD, - CallStackProfileParams::PROCESS_STARTUP, - CallStackProfileParams::MAY_SHUFFLE); - AppendProfiles(params, std::move(profiles)); - ChromeUserMetricsExtension uma_proto; - provider.ProvideCurrentSessionData(&uma_proto); - - ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)), - uma_proto.sampled_profile().size()); - for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) { - SCOPED_TRACE("profile " + base::NumberToString(p)); - VerifyProfileProto(expected_proto_profiles[p], - uma_proto.sampled_profile().Get(p)); - } -} - // Checks that all duplicate samples are collapsed with // preserve_sample_ordering = false. TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) { @@ -371,31 +211,31 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) { base::FilePath module_path("/some/path/to/chrome"); #endif - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .DefineModule(module_name, module_path, module_base_address) - - .AddMilestone(0) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x20) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - - .AddMilestone(1) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x20) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - - .Build(); + Profile profile = + ProfileFactory(100, 10) + .DefineModule(module_name, module_path, module_base_address) + + .AddMilestone(0) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x20) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + + .AddMilestone(1) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x20) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + + .Build(); const ExpectedProtoModule expected_proto_modules[] = { { module_name, module_md5, module_base_address }, @@ -412,33 +252,28 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) { { 0, &expected_proto_entries[1], 1, 1 }, }; - const ExpectedProtoProfile expected_proto_profiles[] = { - { - 100, 10, - expected_proto_modules, arraysize(expected_proto_modules), - expected_proto_samples, arraysize(expected_proto_samples), - }, + const ExpectedProtoProfile expected_proto_profile = { + 100, + 10, + expected_proto_modules, + base::size(expected_proto_modules), + expected_proto_samples, + base::size(expected_proto_samples), }; - ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size()); - CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - AppendProfiles(params, std::move(profiles)); + AppendProfile(params, std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); - ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)), - uma_proto.sampled_profile().size()); - for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) { - SCOPED_TRACE("profile " + base::NumberToString(p)); - VerifyProfileProto(expected_proto_profiles[p], - uma_proto.sampled_profile().Get(p)); - } + ASSERT_EQ(1, uma_proto.sampled_profile().size()); + VerifyProfileProto(expected_proto_profile, + uma_proto.sampled_profile().Get(0)); } // Checks that only contiguous duplicate samples are collapsed with @@ -455,31 +290,31 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) { base::FilePath module_path("/some/path/to/chrome"); #endif - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .DefineModule(module_name, module_path, module_base_address) - - .AddMilestone(0) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x20) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - - .AddMilestone(1) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x20) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - .NewSample() - .AddFrame(0, module_base_address + 0x10) - - .Build(); + Profile profile = + ProfileFactory(100, 10) + .DefineModule(module_name, module_path, module_base_address) + + .AddMilestone(0) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x20) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + + .AddMilestone(1) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x20) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + .NewSample() + .AddFrame(0, module_base_address + 0x10) + + .Build(); const ExpectedProtoModule expected_proto_modules[] = { { module_name, module_md5, module_base_address }, @@ -498,42 +333,36 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) { { 0, &expected_proto_entries[0], 1, 2 }, }; - const ExpectedProtoProfile expected_proto_profiles[] = { - { - 100, 10, - expected_proto_modules, arraysize(expected_proto_modules), - expected_proto_samples, arraysize(expected_proto_samples), - }, + const ExpectedProtoProfile expected_proto_profile = { + 100, + 10, + expected_proto_modules, + base::size(expected_proto_modules), + expected_proto_samples, + base::size(expected_proto_samples), }; - ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size()); - CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::PRESERVE_ORDER); - AppendProfiles(params, std::move(profiles)); + AppendProfile(params, std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); - ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)), - uma_proto.sampled_profile().size()); - for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) { - SCOPED_TRACE("profile " + base::NumberToString(p)); - VerifyProfileProto(expected_proto_profiles[p], - uma_proto.sampled_profile().Get(p)); - } + ASSERT_EQ(1, uma_proto.sampled_profile().size()); + VerifyProfileProto(expected_proto_profile, + uma_proto.sampled_profile().Get(0)); } // Checks that unknown modules produce an empty Entry. TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) { - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); + Profile profile = ProfileFactory(100, 10) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); const ExpectedProtoEntry expected_proto_entries[] = { { -1, 0 }, @@ -542,48 +371,41 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) { { 0, &expected_proto_entries[0], 1, 1 }, }; - const ExpectedProtoProfile expected_proto_profiles[] = { - { - 100, 10, - nullptr, 0, - expected_proto_samples, arraysize(expected_proto_samples), - }, + const ExpectedProtoProfile expected_proto_profile = { + 100, + 10, + nullptr, + 0, + expected_proto_samples, + base::size(expected_proto_samples), }; - ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size()); - CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - AppendProfiles(params, std::move(profiles)); + AppendProfile(params, std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); - ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)), - uma_proto.sampled_profile().size()); - for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) { - SCOPED_TRACE("profile " + base::NumberToString(p)); - VerifyProfileProto(expected_proto_profiles[p], - uma_proto.sampled_profile().Get(p)); - } + ASSERT_EQ(1, uma_proto.sampled_profile().size()); + VerifyProfileProto(expected_proto_profile, + uma_proto.sampled_profile().Get(0)); } -// Checks that pending profiles are only passed back to +// Checks that the pending profile is only passed back to // ProvideCurrentSessionData once. -TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) { +TEST_F(CallStackProfileMetricsProviderTest, ProfileProvidedOnlyOnce) { CallStackProfileMetricsProvider provider; for (int r = 0; r < 2; ++r) { - Profiles profiles = ProfilesFactory() + Profile profile = // Use the sampling period to distinguish the two profiles. - .NewProfile(100, r) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); - - ASSERT_EQ(1U, profiles.size()); + ProfileFactory(100, r) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); @@ -591,7 +413,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) { CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - AppendProfiles(params, std::move(profiles)); + AppendProfile(params, std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); @@ -605,23 +427,20 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) { } } -// Checks that pending profiles are provided to ProvideCurrentSessionData +// Checks that the pending profile is provided to ProvideCurrentSessionData // when collected before CallStackProfileMetricsProvider is instantiated. TEST_F(CallStackProfileMetricsProviderTest, - ProfilesProvidedWhenCollectedBeforeInstantiation) { - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); - - ASSERT_EQ(1U, profiles.size()); + ProfileProvidedWhenCollectedBeforeInstantiation) { + Profile profile = ProfileFactory(100, 10) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - AppendProfiles(params, std::move(profiles)); + AppendProfile(params, std::move(profile)); CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); @@ -631,16 +450,13 @@ TEST_F(CallStackProfileMetricsProviderTest, EXPECT_EQ(1, uma_proto.sampled_profile_size()); } -// Checks that pending profiles are not provided to ProvideCurrentSessionData +// Checks that the pending profile is not provided to ProvideCurrentSessionData // while recording is disabled. -TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) { - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); - - ASSERT_EQ(1U, profiles.size()); +TEST_F(CallStackProfileMetricsProviderTest, ProfileNotProvidedWhileDisabled) { + Profile profile = ProfileFactory(100, 10) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); CallStackProfileMetricsProvider provider; provider.OnRecordingDisabled(); @@ -648,89 +464,86 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) { CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - AppendProfiles(params, std::move(profiles)); + AppendProfile(params, std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); EXPECT_EQ(0, uma_proto.sampled_profile_size()); } -// Checks that pending profiles are not provided to ProvideCurrentSessionData +// Checks that the pending profile is not provided to ProvideCurrentSessionData // if recording is disabled while profiling. TEST_F(CallStackProfileMetricsProviderTest, - ProfilesNotProvidedAfterChangeToDisabled) { + ProfileNotProvidedAfterChangeToDisabled) { CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - base::StackSamplingProfiler::CompletedCallback callback = + CallStackProfileBuilder::CompletedCallback callback = CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess( params); provider.OnRecordingDisabled(); - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); - callback.Run(std::move(profiles)); + Profile profile = ProfileFactory(100, 10) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); + callback.Run(std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); EXPECT_EQ(0, uma_proto.sampled_profile_size()); } -// Checks that pending profiles are not provided to ProvideCurrentSessionData if -// recording is enabled, but then disabled and reenabled while profiling. +// Checks that the pending profile is not provided to ProvideCurrentSessionData +// if recording is enabled, but then disabled and reenabled while profiling. TEST_F(CallStackProfileMetricsProviderTest, - ProfilesNotProvidedAfterChangeToDisabledThenEnabled) { + ProfileNotProvidedAfterChangeToDisabledThenEnabled) { CallStackProfileMetricsProvider provider; provider.OnRecordingEnabled(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - base::StackSamplingProfiler::CompletedCallback callback = + CallStackProfileBuilder::CompletedCallback callback = CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess( params); provider.OnRecordingDisabled(); provider.OnRecordingEnabled(); - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); - callback.Run(std::move(profiles)); + Profile profile = ProfileFactory(100, 10) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); + callback.Run(std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); EXPECT_EQ(0, uma_proto.sampled_profile_size()); } -// Checks that pending profiles are not provided to ProvideCurrentSessionData +// Checks that the pending profile is not provided to ProvideCurrentSessionData // if recording is disabled, but then enabled while profiling. TEST_F(CallStackProfileMetricsProviderTest, - ProfilesNotProvidedAfterChangeFromDisabled) { + ProfileNotProvidedAfterChangeFromDisabled) { CallStackProfileMetricsProvider provider; provider.OnRecordingDisabled(); CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS, CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::MAY_SHUFFLE); - base::StackSamplingProfiler::CompletedCallback callback = + CallStackProfileBuilder::CompletedCallback callback = CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess( params); provider.OnRecordingEnabled(); - Profiles profiles = ProfilesFactory() - .NewProfile(100, 10) - .NewSample() - .AddFrame(Frame::kUnknownModuleIndex, 0x1234) - .Build(); - callback.Run(std::move(profiles)); + Profile profile = ProfileFactory(100, 10) + .NewSample() + .AddFrame(base::kUnknownModuleIndex, 0x1234) + .Build(); + callback.Run(std::move(profile)); ChromeUserMetricsExtension uma_proto; provider.ProvideCurrentSessionData(&uma_proto); diff --git a/chromium/components/metrics/child_call_stack_profile_collector.cc b/chromium/components/metrics/child_call_stack_profile_collector.cc index 978ecd7382c..3cdfc55e7d1 100644 --- a/chromium/components/metrics/child_call_stack_profile_collector.cc +++ b/chromium/components/metrics/child_call_stack_profile_collector.cc @@ -15,30 +15,30 @@ namespace metrics { -ChildCallStackProfileCollector::ProfilesState::ProfilesState() = default; -ChildCallStackProfileCollector::ProfilesState::ProfilesState(ProfilesState&&) = +ChildCallStackProfileCollector::ProfileState::ProfileState() = default; +ChildCallStackProfileCollector::ProfileState::ProfileState(ProfileState&&) = default; -ChildCallStackProfileCollector::ProfilesState::ProfilesState( +ChildCallStackProfileCollector::ProfileState::ProfileState( const CallStackProfileParams& params, base::TimeTicks start_timestamp, - base::StackSamplingProfiler::CallStackProfiles profiles) + base::StackSamplingProfiler::CallStackProfile profile) : params(params), start_timestamp(start_timestamp), - profiles(std::move(profiles)) {} + profile(std::move(profile)) {} -ChildCallStackProfileCollector::ProfilesState::~ProfilesState() = default; +ChildCallStackProfileCollector::ProfileState::~ProfileState() = default; // Some versions of GCC need this for push_back to work with std::move. -ChildCallStackProfileCollector::ProfilesState& -ChildCallStackProfileCollector::ProfilesState::operator=(ProfilesState&&) = +ChildCallStackProfileCollector::ProfileState& +ChildCallStackProfileCollector::ProfileState::operator=(ProfileState&&) = default; ChildCallStackProfileCollector::ChildCallStackProfileCollector() {} ChildCallStackProfileCollector::~ChildCallStackProfileCollector() {} -base::StackSamplingProfiler::CompletedCallback +CallStackProfileBuilder::CompletedCallback ChildCallStackProfileCollector::GetProfilerCallback( const CallStackProfileParams& params, base::TimeTicks profile_start_time) { @@ -59,9 +59,9 @@ void ChildCallStackProfileCollector::SetParentProfileCollector( DCHECK(!parent_collector_); parent_collector_ = std::move(parent_collector); if (parent_collector_) { - for (ProfilesState& state : profiles_) { + for (ProfileState& state : profiles_) { parent_collector_->Collect(state.params, state.start_timestamp, - std::move(state.profiles)); + std::move(state.profile)); } } profiles_.clear(); @@ -70,16 +70,16 @@ void ChildCallStackProfileCollector::SetParentProfileCollector( void ChildCallStackProfileCollector::Collect( const CallStackProfileParams& params, base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles) { + CallStackProfile profile) { // Impl function is used as it needs to PostTask() to itself on a different // thread - which only works with a void return value. - CollectImpl(params, start_timestamp, std::move(profiles)); + CollectImpl(params, start_timestamp, std::move(profile)); } void ChildCallStackProfileCollector::CollectImpl( const CallStackProfileParams& params, base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles) { + CallStackProfile profile) { base::AutoLock alock(lock_); if (task_runner_ && // The profiler thread does not have a task runner. Attempting to @@ -91,15 +91,15 @@ void ChildCallStackProfileCollector::CollectImpl( FROM_HERE, base::BindOnce(&ChildCallStackProfileCollector::CollectImpl, // This class has lazy instance lifetime. base::Unretained(this), params, - start_timestamp, std::move(profiles))); + start_timestamp, std::move(profile))); return; } if (parent_collector_) { - parent_collector_->Collect(params, start_timestamp, std::move(profiles)); + parent_collector_->Collect(params, start_timestamp, std::move(profile)); } else if (retain_profiles_) { profiles_.push_back( - ProfilesState(params, start_timestamp, std::move(profiles))); + ProfileState(params, start_timestamp, std::move(profile))); } } diff --git a/chromium/components/metrics/child_call_stack_profile_collector.h b/chromium/components/metrics/child_call_stack_profile_collector.h index a829f51911a..6e5f331326f 100644 --- a/chromium/components/metrics/child_call_stack_profile_collector.h +++ b/chromium/components/metrics/child_call_stack_profile_collector.h @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" +#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h" namespace service_manager { @@ -41,7 +42,7 @@ namespace metrics { // g_call_stack_profile_collector = LAZY_INSTANCE_INITIALIZER; // // Then, invoke CreateCompletedCallback() to generate the CompletedCallback to -// pass when creating the StackSamplingProfiler. +// pass when creating the CallStackProfileBuilder. // // When the mojo InterfaceProvider becomes available, provide it via // SetParentProfileCollector(). @@ -50,11 +51,11 @@ class ChildCallStackProfileCollector { ChildCallStackProfileCollector(); ~ChildCallStackProfileCollector(); - // Get a callback for use with StackSamplingProfiler that provides completed - // profiles to this object. The callback should be immediately passed to the - // StackSamplingProfiler, and should not be reused between - // StackSamplingProfilers. This function may be called on any thread. - base::StackSamplingProfiler::CompletedCallback GetProfilerCallback( + // Get a callback for use with CallStackProfileBuilder that provides the + // completed profile to this object. The callback should be immediately passed + // to the CallStackProfileBuilder, and should not be reused between + // CallStackProfileBuilders. This function may be called on any thread. + CallStackProfileBuilder::CompletedCallback GetProfilerCallback( const CallStackProfileParams& params, base::TimeTicks profile_start_time); @@ -67,39 +68,38 @@ class ChildCallStackProfileCollector { private: friend class ChildCallStackProfileCollectorTest; - // Bundles together a set of collected profiles and the collection state for - // storage, pending availability of the parent mojo interface. |profiles| + // Bundles together a collected profile and the collection state for + // storage, pending availability of the parent mojo interface. |profile| // is not const& because it must be passed with std::move. - struct ProfilesState { - ProfilesState(); - ProfilesState(ProfilesState&&); - ProfilesState( - const CallStackProfileParams& params, - base::TimeTicks start_timestamp, - base::StackSamplingProfiler::CallStackProfiles profiles); - ~ProfilesState(); + struct ProfileState { + ProfileState(); + ProfileState(ProfileState&&); + ProfileState(const CallStackProfileParams& params, + base::TimeTicks start_timestamp, + base::StackSamplingProfiler::CallStackProfile profile); + ~ProfileState(); - ProfilesState& operator=(ProfilesState&&); + ProfileState& operator=(ProfileState&&); CallStackProfileParams params; base::TimeTicks start_timestamp; - // The sampled profiles. - base::StackSamplingProfiler::CallStackProfiles profiles; + // The sampled profile. + base::StackSamplingProfiler::CallStackProfile profile; private: - DISALLOW_COPY_AND_ASSIGN(ProfilesState); + DISALLOW_COPY_AND_ASSIGN(ProfileState); }; using CallStackProfile = base::StackSamplingProfiler::CallStackProfile; void Collect(const CallStackProfileParams& params, base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles); + CallStackProfile profile); void CollectImpl(const CallStackProfileParams& params, base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles); + CallStackProfile profile); // This object may be accessed on any thread, including the profiler // thread. The expected use case for the object is to be created and have @@ -107,7 +107,7 @@ class ChildCallStackProfileCollector { // of PostTask and the like for inter-thread communication. base::Lock lock_; - // Whether to retain profiles when the interface is not set. Remains true + // Whether to retain the profile when the interface is not set. Remains true // until the invocation of SetParentProfileCollector(), at which point it is // false for the rest of the object lifetime. bool retain_profiles_ = true; @@ -123,7 +123,7 @@ class ChildCallStackProfileCollector { // Profiles being cached by this object, pending a parent interface to be // supplied. - std::vector<ProfilesState> profiles_; + std::vector<ProfileState> profiles_; DISALLOW_COPY_AND_ASSIGN(ChildCallStackProfileCollector); }; diff --git a/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc index 8bf1c5b7ca8..aa924cb0bc7 100644 --- a/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc +++ b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc @@ -19,11 +19,6 @@ namespace metrics { -namespace { - - -} // namespace - class ChildCallStackProfileCollectorTest : public testing::Test { protected: class Receiver : public mojom::CallStackProfileCollector { @@ -36,14 +31,12 @@ class ChildCallStackProfileCollectorTest : public testing::Test { void Collect(const CallStackProfileParams& params, base::TimeTicks start_timestamp, - std::vector<CallStackProfile> profiles) override { - this->profiles.push_back(ChildCallStackProfileCollector::ProfilesState( - params, - start_timestamp, - std::move(profiles))); + CallStackProfile profile) override { + this->profiles.push_back(ChildCallStackProfileCollector::ProfileState( + params, start_timestamp, std::move(profile))); } - std::vector<ChildCallStackProfileCollector::ProfilesState> profiles; + std::vector<ChildCallStackProfileCollector::ProfileState> profiles; private: mojo::Binding<mojom::CallStackProfileCollector> binding_; @@ -54,18 +47,14 @@ class ChildCallStackProfileCollectorTest : public testing::Test { ChildCallStackProfileCollectorTest() : receiver_impl_(new Receiver(MakeRequest(&receiver_))) {} - void CollectEmptyProfiles( - const CallStackProfileParams& params, - size_t profile_count) { - base::StackSamplingProfiler::CallStackProfiles profiles; - for (size_t i = 0; i < profile_count; ++i) - profiles.push_back(base::StackSamplingProfiler::CallStackProfile()); + void CollectEmptyProfile(const CallStackProfileParams& params) { + base::StackSamplingProfiler::CallStackProfile profile; child_collector_.GetProfilerCallback(params, base::TimeTicks::Now()) - .Run(std::move(profiles)); + .Run(std::move(profile)); } - const std::vector<ChildCallStackProfileCollector::ProfilesState>& - profiles() const { + const std::vector<ChildCallStackProfileCollector::ProfileState>& profiles() + const { return child_collector_.profiles_; } @@ -82,13 +71,11 @@ class ChildCallStackProfileCollectorTest : public testing::Test { TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) { EXPECT_EQ(0u, profiles().size()); - // Add profiles before providing the interface. - CollectEmptyProfiles( - CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, - CallStackProfileParams::MAIN_THREAD, - CallStackProfileParams::JANKY_TASK, - CallStackProfileParams::PRESERVE_ORDER), - 2); + // Add a profile before providing the interface. + CollectEmptyProfile(CallStackProfileParams( + CallStackProfileParams::BROWSER_PROCESS, + CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::JANKY_TASK, + CallStackProfileParams::PRESERVE_ORDER)); ASSERT_EQ(1u, profiles().size()); EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS, profiles()[0].params.process); @@ -99,7 +86,6 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) { base::TimeTicks start_timestamp = profiles()[0].start_timestamp; EXPECT_GE(base::TimeDelta::FromMilliseconds(10), base::TimeTicks::Now() - start_timestamp); - EXPECT_EQ(2u, profiles()[0].profiles.size()); // Set the interface. The profiles should be passed to it. child_collector_.SetParentProfileCollector(std::move(receiver_)); @@ -111,17 +97,13 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) { EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER, receiver_impl_->profiles[0].params.ordering_spec); EXPECT_EQ(start_timestamp, receiver_impl_->profiles[0].start_timestamp); - EXPECT_EQ(2u, receiver_impl_->profiles[0].profiles.size()); - // Add profiles after providing the interface. They should also be passed to - // it. + // Add a profile after providing the interface. It should also be passed. receiver_impl_->profiles.clear(); - CollectEmptyProfiles( - CallStackProfileParams(CallStackProfileParams::GPU_PROCESS, - CallStackProfileParams::MAIN_THREAD, - CallStackProfileParams::THREAD_HUNG, - CallStackProfileParams::PRESERVE_ORDER), - 1); + CollectEmptyProfile(CallStackProfileParams( + CallStackProfileParams::GPU_PROCESS, CallStackProfileParams::MAIN_THREAD, + CallStackProfileParams::THREAD_HUNG, + CallStackProfileParams::PRESERVE_ORDER)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(0u, profiles().size()); ASSERT_EQ(1u, receiver_impl_->profiles.size()); @@ -136,19 +118,16 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) { EXPECT_GE(base::TimeDelta::FromMilliseconds(10), (base::TimeTicks::Now() - receiver_impl_->profiles[0].start_timestamp)); - EXPECT_EQ(1u, receiver_impl_->profiles[0].profiles.size()); } TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) { EXPECT_EQ(0u, profiles().size()); - // Add profiles before providing a null interface. - CollectEmptyProfiles( - CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, - CallStackProfileParams::MAIN_THREAD, - CallStackProfileParams::JANKY_TASK, - CallStackProfileParams::PRESERVE_ORDER), - 2); + // Add a profile before providing a null interface. + CollectEmptyProfile(CallStackProfileParams( + CallStackProfileParams::BROWSER_PROCESS, + CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::JANKY_TASK, + CallStackProfileParams::PRESERVE_ORDER)); ASSERT_EQ(1u, profiles().size()); EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS, profiles()[0].params.process); @@ -158,21 +137,19 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) { profiles()[0].params.ordering_spec); EXPECT_GE(base::TimeDelta::FromMilliseconds(10), base::TimeTicks::Now() - profiles()[0].start_timestamp); - EXPECT_EQ(2u, profiles()[0].profiles.size()); - // Set the null interface. The profiles should be flushed. + // Set the null interface. The profile should be flushed. child_collector_.SetParentProfileCollector( mojom::CallStackProfileCollectorPtr()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(0u, profiles().size()); - // Add profiles after providing a null interface. They should also be flushed. - CollectEmptyProfiles( - CallStackProfileParams(CallStackProfileParams::GPU_PROCESS, - CallStackProfileParams::MAIN_THREAD, - CallStackProfileParams::THREAD_HUNG, - CallStackProfileParams::PRESERVE_ORDER), - 1); + // Add a profile after providing a null interface. They should also be + // flushed. + CollectEmptyProfile(CallStackProfileParams( + CallStackProfileParams::GPU_PROCESS, CallStackProfileParams::MAIN_THREAD, + CallStackProfileParams::THREAD_HUNG, + CallStackProfileParams::PRESERVE_ORDER)); EXPECT_EQ(0u, profiles().size()); } diff --git a/chromium/components/metrics/generate_expired_histograms_array.gni b/chromium/components/metrics/generate_expired_histograms_array.gni index b211c6676a8..b4522465325 100644 --- a/chromium/components/metrics/generate_expired_histograms_array.gni +++ b/chromium/components/metrics/generate_expired_histograms_array.gni @@ -46,7 +46,7 @@ template("generate_expired_histograms_array") { "-o" + rebase_path(root_gen_dir, root_build_dir), "-H" + rebase_path(header_filename, root_gen_dir), "-d" + rebase_path(major_branch_date_filepath, root_build_dir), - "-m" + rebase_path(milestone_filepath), + "-m" + rebase_path(milestone_filepath, root_build_dir), ] + rebase_path(inputs, root_build_dir) } } diff --git a/chromium/components/metrics/gpu/gpu_metrics_provider.cc b/chromium/components/metrics/gpu/gpu_metrics_provider.cc index 7eacbe710ee..53c15fb7c87 100644 --- a/chromium/components/metrics/gpu/gpu_metrics_provider.cc +++ b/chromium/components/metrics/gpu/gpu_metrics_provider.cc @@ -23,12 +23,13 @@ void GPUMetricsProvider::ProvideSystemProfileMetrics( const gpu::GPUInfo& gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo(); + const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu(); SystemProfileProto::Hardware::Graphics* gpu = hardware->mutable_gpu(); - gpu->set_vendor_id(gpu_info.gpu.vendor_id); - gpu->set_device_id(gpu_info.gpu.device_id); - gpu->set_driver_version(gpu_info.driver_version); - gpu->set_driver_date(gpu_info.driver_date); + gpu->set_vendor_id(active_gpu.vendor_id); + gpu->set_device_id(active_gpu.device_id); + gpu->set_driver_version(active_gpu.driver_version); + gpu->set_driver_date(active_gpu.driver_date); gpu->set_gl_vendor(gpu_info.gl_vendor); gpu->set_gl_renderer(gpu_info.gl_renderer); } diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc index a99d3c7489c..e7504d351c8 100644 --- a/chromium/components/metrics/metrics_log.cc +++ b/chromium/components/metrics/metrics_log.cc @@ -19,6 +19,7 @@ #include "base/metrics/histogram_snapshot_manager.h" #include "base/metrics/metrics_hashes.h" #include "base/strings/string_piece.h" +#include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "base/time/time.h" #include "build/build_config.h" @@ -170,7 +171,9 @@ void MetricsLog::RecordCoreSystemProfile(MetricsServiceClient* client, metrics::SystemProfileProto::OS* os = system_profile->mutable_os(); os->set_name(base::SysInfo::OperatingSystemName()); os->set_version(base::SysInfo::OperatingSystemVersion()); -#if defined(OS_ANDROID) +#if defined(OS_CHROMEOS) + os->set_kernel_version(base::SysInfo::KernelVersion()); +#elif defined(OS_ANDROID) os->set_build_fingerprint( base::android::BuildInfo::GetInstance()->android_build_fp()); std::string package_name = client->GetAppPackageName(); diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc index c4250180a6d..8af49a8cbbc 100644 --- a/chromium/components/metrics/metrics_log_unittest.cc +++ b/chromium/components/metrics/metrics_log_unittest.cc @@ -15,6 +15,7 @@ #include "base/metrics/bucket_ranges.h" #include "base/metrics/sample_vector.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "base/time/time.h" #include "components/metrics/delegating_provider.h" @@ -153,7 +154,10 @@ TEST_F(MetricsLogTest, BasicRecord) { system_profile->mutable_os()->set_name(base::SysInfo::OperatingSystemName()); system_profile->mutable_os()->set_version( base::SysInfo::OperatingSystemVersion()); -#if defined(OS_ANDROID) +#if defined(OS_CHROMEOS) + system_profile->mutable_os()->set_kernel_version( + base::SysInfo::KernelVersion()); +#elif defined(OS_ANDROID) system_profile->mutable_os()->set_build_fingerprint( base::android::BuildInfo::GetInstance()->android_build_fp()); system_profile->set_app_package_name("test app"); diff --git a/chromium/components/metrics/metrics_state_manager_unittest.cc b/chromium/components/metrics/metrics_state_manager_unittest.cc index 3e27e1a2696..0e1f1481c64 100644 --- a/chromium/components/metrics/metrics_state_manager_unittest.cc +++ b/chromium/components/metrics/metrics_state_manager_unittest.cc @@ -14,7 +14,7 @@ #include "base/command_line.h" #include "base/macros.h" #include "base/strings/string16.h" -#include "base/test/histogram_tester.h" +#include "base/test/metrics/histogram_tester.h" #include "components/metrics/client_info.h" #include "components/metrics/metrics_log.h" #include "components/metrics/metrics_pref_names.h" diff --git a/chromium/components/metrics/net/net_metrics_log_uploader.cc b/chromium/components/metrics/net/net_metrics_log_uploader.cc index cbe1f0a0582..addad6b9f1a 100644 --- a/chromium/components/metrics/net/net_metrics_log_uploader.cc +++ b/chromium/components/metrics/net/net_metrics_log_uploader.cc @@ -12,6 +12,7 @@ #include "components/encrypted_messages/message_encrypter.h" #include "components/metrics/metrics_log_uploader.h" #include "net/base/load_flags.h" +#include "net/base/url_util.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/url_fetcher.h" #include "third_party/metrics_proto/reporting_info.pb.h" @@ -195,8 +196,10 @@ void NetMetricsLogUploader::UploadLogToURL( service); current_fetch_->SetRequestContext(request_context_getter_); std::string reporting_info_string = SerializeReportingInfo(reporting_info); - // If we are not using HTTPS for this upload, encrypt it. - if (!url.SchemeIs(url::kHttpsScheme)) { + // If we are not using HTTPS for this upload, encrypt it. We do not encrypt + // requests to localhost to allow testing with a local collector that doesn't + // have decryption enabled. + if (!url.SchemeIs(url::kHttpsScheme) && !net::IsLocalhost(url)) { std::string encrypted_message; if (!EncryptString(compressed_log_data, &encrypted_message)) { current_fetch_.reset(); diff --git a/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc b/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc index 7f7747e43e5..76652ec3968 100644 --- a/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc +++ b/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc @@ -32,11 +32,10 @@ class NetMetricsLogUploaderTest : public testing::Test { reporting_info); } - void CreateUploaderAndUploadToSecureURL() { + void CreateUploaderAndUploadToSecureURL(const std::string& url) { ReportingInfo dummy_reporting_info; uploader_.reset(new NetMetricsLogUploader( - nullptr, "https://dummy_secure_server", "dummy_mime", - MetricsLogUploader::UMA, + nullptr, url, "dummy_mime", MetricsLogUploader::UMA, base::Bind(&NetMetricsLogUploaderTest::DummyOnUploadComplete, base::Unretained(this)))); uploader_->UploadLog("dummy_data", "dummy_hash", dummy_reporting_info); @@ -128,7 +127,16 @@ TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPIsEncrypted) { // message. TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPSIsNotEncrypted) { net::TestURLFetcherFactory factory; - CreateUploaderAndUploadToSecureURL(); + CreateUploaderAndUploadToSecureURL("https://dummy_secure_server"); + net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); + EXPECT_EQ(fetcher->upload_data(), "dummy_data"); +} + +// Test that attempting to upload to localhost over http results in an +// unencrypted message. +TEST_F(NetMetricsLogUploaderTest, MessageOverHTTPLocalhostIsNotEncrypted) { + net::TestURLFetcherFactory factory; + CreateUploaderAndUploadToSecureURL("http://localhost"); net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); EXPECT_EQ(fetcher->upload_data(), "dummy_data"); } diff --git a/chromium/components/metrics/net/network_metrics_provider.cc b/chromium/components/metrics/net/network_metrics_provider.cc index 412f0afbb40..a0cdd391a03 100644 --- a/chromium/components/metrics/net/network_metrics_provider.cc +++ b/chromium/components/metrics/net/network_metrics_provider.cc @@ -208,6 +208,8 @@ void NetworkMetricsProvider::ProvideSystemProfileMetrics( // window, since OnConnectionTypeChanged() ignores transitions to the "none" // state. connection_type_ = net::NetworkChangeNotifier::GetConnectionType(); + if (connection_type_ != net::NetworkChangeNotifier::CONNECTION_UNKNOWN) + network_change_notifier_initialized_ = true; // Reset the "ambiguous" flags, since a new metrics log session has started. connection_type_is_ambiguous_ = false; wifi_phy_layer_protocol_is_ambiguous_ = false; @@ -415,7 +417,7 @@ void NetworkMetricsProvider::WriteWifiAccessPointProto( void NetworkMetricsProvider::LogAggregatedMetrics() { DCHECK(thread_checker_.CalledOnValidThread()); base::HistogramBase* error_codes = base::SparseHistogram::FactoryGet( - "Net.ErrorCodesForMainFrame3", + "Net.ErrorCodesForMainFrame4", base::HistogramBase::kUmaTargetedHistogramFlag); std::unique_ptr<base::HistogramSamples> samples = error_codes->SnapshotSamples(); diff --git a/chromium/components/metrics/net/network_metrics_provider.h b/chromium/components/metrics/net/network_metrics_provider.h index c1a0312efb6..f0f6d0e0334 100644 --- a/chromium/components/metrics/net/network_metrics_provider.h +++ b/chromium/components/metrics/net/network_metrics_provider.h @@ -125,7 +125,7 @@ class NetworkMetricsProvider // Helper object for retrieving connected wifi access point information. std::unique_ptr<WifiAccessPointInfoProvider> wifi_access_point_info_provider_; - // These metrics track histogram totals for the Net.ErrorCodesForMainFrame3 + // These metrics track histogram totals for the Net.ErrorCodesForMainFrame4 // histogram. They are used to compute deltas at upload time. base::HistogramBase::Count total_aborts_; base::HistogramBase::Count total_codes_; diff --git a/chromium/components/metrics/public/cpp/OWNERS b/chromium/components/metrics/public/cpp/OWNERS index 154435234ea..2c44a463856 100644 --- a/chromium/components/metrics/public/cpp/OWNERS +++ b/chromium/components/metrics/public/cpp/OWNERS @@ -2,3 +2,5 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS per-file *_struct_traits*.*=set noparent per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS diff --git a/chromium/components/metrics/public/cpp/call_stack_profile.typemap b/chromium/components/metrics/public/cpp/call_stack_profile.typemap index 611148c8255..aa8456507d3 100644 --- a/chromium/components/metrics/public/cpp/call_stack_profile.typemap +++ b/chromium/components/metrics/public/cpp/call_stack_profile.typemap @@ -12,7 +12,7 @@ traits_headers = [ "//components/metrics/public/cpp/call_stack_profile_struct_traits.h" ] deps = [ "//base", - "//components/metrics:call_stack_profile_params", + "//components/metrics:call_stack_profile", ] type_mappings = [ "metrics.mojom.CallStackModule=base::StackSamplingProfiler::Module", diff --git a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h index 98aae66fd70..b062a5a0497 100644 --- a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h +++ b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h @@ -56,17 +56,16 @@ struct StructTraits<metrics::mojom::CallStackFrameDataView, } static uint64_t module_index( const base::StackSamplingProfiler::Frame& frame) { - return frame.module_index == - base::StackSamplingProfiler::Frame::kUnknownModuleIndex ? - static_cast<uint64_t>(-1) : - frame.module_index; + return frame.module_index == base::kUnknownModuleIndex + ? static_cast<uint64_t>(-1) + : frame.module_index; } static bool Read(metrics::mojom::CallStackFrameDataView data, base::StackSamplingProfiler::Frame* out) { - size_t module_index = data.module_index() == static_cast<uint64_t>(-1) ? - base::StackSamplingProfiler::Frame::kUnknownModuleIndex : - data.module_index(); + size_t module_index = data.module_index() == static_cast<uint64_t>(-1) + ? base::kUnknownModuleIndex + : data.module_index(); // We can't know whether the module_index field is valid at this point since // we don't have access to the number of modules here. This will be checked @@ -128,8 +127,7 @@ struct StructTraits<metrics::mojom::CallStackProfileDataView, for (const base::StackSamplingProfiler::Sample& sample : samples) { for (const base::StackSamplingProfiler::Frame& frame : sample.frames) { if (frame.module_index >= module_count && - frame.module_index != - base::StackSamplingProfiler::Frame::kUnknownModuleIndex) + frame.module_index != base::kUnknownModuleIndex) return false; } } diff --git a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc index 7bdb4dbb085..b0d2bf0288b 100644 --- a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc +++ b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc @@ -151,20 +151,20 @@ TEST_F(CallStackProfileStructTraitsTest, Frame) { using Frame = base::StackSamplingProfiler::Frame; const Frame serialize_cases[] = { - // Null instruction pointer. - Frame(0x0, 10), - // Non-null instruction pointer. - Frame(0x10, 10), - // Instruction pointer with a bit set beyond 32 bits, when built for x64. - Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10), - // Zero module index. - Frame(0xabcd, 0), - // Non-zero module index. - Frame(0xabcd, 1), - // Non-zero module index. - Frame(0xabcd, 10), - // Unknown module index. - Frame(0xabcd, Frame::kUnknownModuleIndex), + // Null instruction pointer. + Frame(0x0, 10), + // Non-null instruction pointer. + Frame(0x10, 10), + // Instruction pointer with a bit set beyond 32 bits, when built for x64. + Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10), + // Zero module index. + Frame(0xabcd, 0), + // Non-zero module index. + Frame(0xabcd, 1), + // Non-zero module index. + Frame(0xabcd, 10), + // Unknown module index. + Frame(0xabcd, base::kUnknownModuleIndex), }; for (const Frame& input : serialize_cases) { @@ -179,10 +179,11 @@ TEST_F(CallStackProfileStructTraitsTest, Frame) { // Checks serialization/deserialization of Profile fields, including validation // of the Frame module_index field. TEST_F(CallStackProfileStructTraitsTest, Profile) { - using Module = base::StackSamplingProfiler::Module; - using Frame = base::StackSamplingProfiler::Frame; - using Sample = base::StackSamplingProfiler::Sample; - using Profile = base::StackSamplingProfiler::CallStackProfile; + using base::StackSamplingProfiler; + using Module = StackSamplingProfiler::Module; + using Frame = StackSamplingProfiler::Frame; + using Sample = StackSamplingProfiler::Sample; + using Profile = StackSamplingProfiler::CallStackProfile; struct SerializeCase { Profile profile; @@ -190,60 +191,49 @@ TEST_F(CallStackProfileStructTraitsTest, Profile) { }; const SerializeCase serialize_cases[] = { - // Empty modules and samples. - { - CreateProfile(std::vector<Module>(), std::vector<Sample>(), - base::TimeDelta::FromSeconds(1), - base::TimeDelta::FromSeconds(2)), - true - }, - // Non-empty modules and empty samples. - { - CreateProfile({ Module(0x4000, "a", base::FilePath()) }, - std::vector<Sample>(), - base::TimeDelta::FromSeconds(1), - base::TimeDelta::FromSeconds(2)), - true - }, - // Valid values for modules and samples. - { - CreateProfile({ - Module(0x4000, "a", base::FilePath()), - Module(0x4100, "b", base::FilePath()), - }, - { - Sample({ - Frame(0x4010, 0), - Frame(0x4110, 1), - Frame(0x4110, Frame::kUnknownModuleIndex), - }), - }, - base::TimeDelta::FromSeconds(1), - base::TimeDelta::FromSeconds(2)), - true - }, - // Valid values for modules, but an out of range module index in the second - // sample. - { - CreateProfile({ - Module(0x4000, "a", base::FilePath()), - Module(0x4100, "b", base::FilePath()), - }, - { - Sample({ - Frame(0x4010, 0), - Frame(0x4110, 1), - Frame(0x4110, Frame::kUnknownModuleIndex), - }), - Sample({ - Frame(0x4010, 0), - Frame(0x4110, 2), - }), - }, - base::TimeDelta::FromSeconds(1), - base::TimeDelta::FromSeconds(2)), - false - }, + // Empty modules and samples. + {CreateProfile(std::vector<Module>(), std::vector<Sample>(), + base::TimeDelta::FromSeconds(1), + base::TimeDelta::FromSeconds(2)), + true}, + // Non-empty modules and empty samples. + {CreateProfile({Module(0x4000, "a", base::FilePath())}, + std::vector<Sample>(), base::TimeDelta::FromSeconds(1), + base::TimeDelta::FromSeconds(2)), + true}, + // Valid values for modules and samples. + {CreateProfile( + { + Module(0x4000, "a", base::FilePath()), + Module(0x4100, "b", base::FilePath()), + }, + { + Sample({ + Frame(0x4010, 0), Frame(0x4110, 1), + Frame(0x4110, base::kUnknownModuleIndex), + }), + }, + base::TimeDelta::FromSeconds(1), base::TimeDelta::FromSeconds(2)), + true}, + // Valid values for modules, but an out of range module index in the + // second + // sample. + {CreateProfile( + { + Module(0x4000, "a", base::FilePath()), + Module(0x4100, "b", base::FilePath()), + }, + { + Sample({ + Frame(0x4010, 0), Frame(0x4110, 1), + Frame(0x4110, base::kUnknownModuleIndex), + }), + Sample({ + Frame(0x4010, 0), Frame(0x4110, 2), + }), + }, + base::TimeDelta::FromSeconds(1), base::TimeDelta::FromSeconds(2)), + false}, }; for (const SerializeCase& input : serialize_cases) { diff --git a/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom b/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom index d265d606e89..8f0031db654 100644 --- a/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom +++ b/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom @@ -74,5 +74,5 @@ struct CallStackProfileParams { interface CallStackProfileCollector { Collect(CallStackProfileParams params, mojo_base.mojom.TimeTicks start_timestamp, - array<CallStackProfile> profiles); + CallStackProfile profile); }; diff --git a/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc b/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc index f9fbbba6c44..cec7c869c12 100644 --- a/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc +++ b/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc @@ -8,7 +8,7 @@ #include "base/metrics/dummy_histogram.h" #include "base/run_loop.h" #include "base/test/gtest_util.h" -#include "base/test/histogram_tester.h" +#include "base/test/metrics/histogram_tester.h" #include "base/threading/thread.h" #include "components/metrics/single_sample_metrics.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc index 375f75c4368..517fc71fc86 100644 --- a/chromium/components/metrics/stability_metrics_helper.cc +++ b/chromium/components/metrics/stability_metrics_helper.cc @@ -17,6 +17,7 @@ #include "components/metrics/metrics_pref_names.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "components/variations/hashing.h" #include "extensions/buildflags/buildflags.h" #include "third_party/metrics_proto/system_profile.pb.h" @@ -188,6 +189,23 @@ void StabilityMetricsHelper::IncreaseRendererCrashCount() { IncrementPrefValue(prefs::kStabilityRendererCrashCount); } +void StabilityMetricsHelper::BrowserUtilityProcessLaunched( + const std::string& metrics_name) { + uint32_t hash = variations::HashName(metrics_name); + base::UmaHistogramSparse("ChildProcess.Launched.UtilityProcessHash", hash); +} + +void StabilityMetricsHelper::BrowserUtilityProcessCrashed( + const std::string& metrics_name, + int exit_code) { + // TODO(wfh): there doesn't appear to be a good way to log these exit_codes + // without adding something into the stability proto, so for now only log the + // crash and if the numbers are high enough, logging exit codes can be added + // later. + uint32_t hash = variations::HashName(metrics_name); + base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessHash", hash); +} + void StabilityMetricsHelper::BrowserChildProcessCrashed() { IncrementPrefValue(prefs::kStabilityChildProcessCrashCount); } diff --git a/chromium/components/metrics/stability_metrics_helper.h b/chromium/components/metrics/stability_metrics_helper.h index ddf4d50c597..5a22882af4b 100644 --- a/chromium/components/metrics/stability_metrics_helper.h +++ b/chromium/components/metrics/stability_metrics_helper.h @@ -30,6 +30,13 @@ class StabilityMetricsHelper { // Clears the gathered stability metrics. void ClearSavedStabilityMetrics(); + // Records a utility process launch with name |metrics_name|. + void BrowserUtilityProcessLaunched(const std::string& metrics_name); + + // Records a utility process crash with name |metrics_name|. + void BrowserUtilityProcessCrashed(const std::string& metrics_name, + int exit_code); + // Records a browser child process crash. void BrowserChildProcessCrashed(); diff --git a/chromium/components/metrics/stability_metrics_helper_unittest.cc b/chromium/components/metrics/stability_metrics_helper_unittest.cc index bcaa2c1e017..66fc041db09 100644 --- a/chromium/components/metrics/stability_metrics_helper_unittest.cc +++ b/chromium/components/metrics/stability_metrics_helper_unittest.cc @@ -7,7 +7,7 @@ #include <memory> #include "base/macros.h" -#include "base/test/histogram_tester.h" +#include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" diff --git a/chromium/components/metrics/stability_metrics_provider_unittest.cc b/chromium/components/metrics/stability_metrics_provider_unittest.cc index 3a188ec3f83..e0ba0ce9ba7 100644 --- a/chromium/components/metrics/stability_metrics_provider_unittest.cc +++ b/chromium/components/metrics/stability_metrics_provider_unittest.cc @@ -4,7 +4,7 @@ #include "components/metrics/stability_metrics_provider.h" -#include "base/test/histogram_tester.h" +#include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" #include "components/prefs/testing_pref_service.h" #include "testing/gtest/include/gtest/gtest.h" |