Commit 4dec7e4b authored by Xi Cheng's avatar Xi Cheng Committed by Commit Bot

Directly write SampledProfile protocol buffer message and send over mojo

This change removes the current execution profile _mojo_ representation
in favor of directly writing the data in the protocol buffer format used
for UMA upload. The reasons for using this format are:
1. it's the format that we ultimately need the data in;
2. it's the most memory-efficient representation available to us, because
   of the protocol buffer varint encoding;
3. the serialized protocol buffers are trivially compressible.

We generate execution profiles in non-browser processes, so this means
writing the protocol buffer representation in those processes and sending
over mojo to the browser process, where the UMA upload takes place.

We're making this change as part of a refactoring to expand the profiling
scenarios supported by the UMA Sampling Profiler. A key aspect of this
refactoring is reducing memory consumption of the execution profile
representation. See http://crbug.com/850148 for examples of memory usage
problems with this representation.

Bug: 851163, 804942
Change-Id: Ied88d6fd932587707c1f5a4c79acd77d5911f6ee
Reviewed-on: https://chromium-review.googlesource.com/1157547
Commit-Queue: Mike Wittman <wittman@chromium.org>
Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Reviewed-by: default avatarMike Wittman <wittman@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582209}
parent ce3a5818
...@@ -136,7 +136,6 @@ ...@@ -136,7 +136,6 @@
#include "components/language/core/common/language_experiments.h" #include "components/language/core/common/language_experiments.h"
#include "components/language_usage_metrics/language_usage_metrics.h" #include "components/language_usage_metrics/language_usage_metrics.h"
#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/call_stack_profile_metrics_provider.h"
#include "components/metrics/call_stack_profile_params.h" #include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/expired_histogram_util.h" #include "components/metrics/expired_histogram_util.h"
#include "components/metrics/metrics_reporting_default_state.h" #include "components/metrics/metrics_reporting_default_state.h"
...@@ -2114,7 +2113,7 @@ void ChromeBrowserMainParts::PostMainMessageLoopRun() { ...@@ -2114,7 +2113,7 @@ void ChromeBrowserMainParts::PostMainMessageLoopRun() {
void ChromeBrowserMainParts::PreShutdown() { void ChromeBrowserMainParts::PreShutdown() {
metrics::CallStackProfileBuilder::SetProcessMilestone( metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileMetricsProvider::SHUTDOWN_START); metrics::CallStackProfileBuilder::SHUTDOWN_START);
} }
void ChromeBrowserMainParts::PostDestroyThreads() { void ChromeBrowserMainParts::PostDestroyThreads() {
......
...@@ -57,6 +57,9 @@ include_rules = [ ...@@ -57,6 +57,9 @@ include_rules = [
"+third_party/blink/public/platform/web_client_hints_types.mojom.h", "+third_party/blink/public/platform/web_client_hints_types.mojom.h",
"+third_party/blink/public/platform/web_feature.mojom.h", "+third_party/blink/public/platform/web_feature.mojom.h",
# Temporary dependency for thread_profiler.h. TODO(chengx): remove this dependency.
"+third_party/metrics_proto/sampled_profile.pb.h",
# FIXME - refactor code and remove these dependencies # FIXME - refactor code and remove these dependencies
"+chrome/installer/util", "+chrome/installer/util",
] ]
...@@ -196,12 +196,12 @@ ThreadProfiler::ThreadProfiler( ...@@ -196,12 +196,12 @@ ThreadProfiler::ThreadProfiler(
if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess()) if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
return; return;
auto profile_builder = auto profile_builder = std::make_unique<CallStackProfileBuilder>(
std::make_unique<CallStackProfileBuilder>(BindRepeating( BindRepeating(&ThreadProfiler::ReceiveStartupProfile,
&ThreadProfiler::ReceiveStartupProfile, GetReceiverCallback()),
GetReceiverCallback(CallStackProfileParams( CallStackProfileParams(GetProcess(), thread,
GetProcess(), thread, CallStackProfileParams::PROCESS_STARTUP, CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE)))); CallStackProfileParams::MAY_SHUFFLE));
startup_profiler_ = std::make_unique<StackSamplingProfiler>( startup_profiler_ = std::make_unique<StackSamplingProfiler>(
base::PlatformThread::CurrentId(), kSamplingParams, base::PlatformThread::CurrentId(), kSamplingParams,
...@@ -225,8 +225,8 @@ ThreadProfiler::ThreadProfiler( ...@@ -225,8 +225,8 @@ ThreadProfiler::ThreadProfiler(
ScheduleNextPeriodicCollection(); ScheduleNextPeriodicCollection();
} }
CallStackProfileBuilder::CompletedCallback ThreadProfiler::GetReceiverCallback( CallStackProfileBuilder::CompletedCallback
const CallStackProfileParams& profile_params) { ThreadProfiler::GetReceiverCallback() {
// TODO(wittman): Simplify the approach to getting the profiler callback // TODO(wittman): Simplify the approach to getting the profiler callback
// across CallStackProfileMetricsProvider and // across CallStackProfileMetricsProvider and
// ChildCallStackProfileCollector. Ultimately both should expose functions // ChildCallStackProfileCollector. Ultimately both should expose functions
...@@ -242,17 +242,16 @@ CallStackProfileBuilder::CompletedCallback ThreadProfiler::GetReceiverCallback( ...@@ -242,17 +242,16 @@ CallStackProfileBuilder::CompletedCallback ThreadProfiler::GetReceiverCallback(
base::TimeTicks profile_start_time = base::TimeTicks::Now(); base::TimeTicks profile_start_time = base::TimeTicks::Now();
if (GetProcess() == CallStackProfileParams::BROWSER_PROCESS) { if (GetProcess() == CallStackProfileParams::BROWSER_PROCESS) {
return metrics::CallStackProfileMetricsProvider:: return metrics::CallStackProfileMetricsProvider::
GetProfilerCallbackForBrowserProcess(profile_params); GetProfilerCallbackForBrowserProcess();
} }
return g_child_call_stack_profile_collector.Get() return g_child_call_stack_profile_collector.Get()
.ChildCallStackProfileCollector::GetProfilerCallback(profile_params, .ChildCallStackProfileCollector::GetProfilerCallback(profile_start_time);
profile_start_time);
} }
// static // static
void ThreadProfiler::ReceiveStartupProfile( void ThreadProfiler::ReceiveStartupProfile(
const CallStackProfileBuilder::CompletedCallback& receiver_callback, const CallStackProfileBuilder::CompletedCallback& receiver_callback,
StackSamplingProfiler::CallStackProfile profile) { metrics::SampledProfile profile) {
receiver_callback.Run(std::move(profile)); receiver_callback.Run(std::move(profile));
} }
...@@ -261,7 +260,7 @@ void ThreadProfiler::ReceivePeriodicProfile( ...@@ -261,7 +260,7 @@ void ThreadProfiler::ReceivePeriodicProfile(
const CallStackProfileBuilder::CompletedCallback& receiver_callback, const CallStackProfileBuilder::CompletedCallback& receiver_callback,
scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner, scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner,
base::WeakPtr<ThreadProfiler> thread_profiler, base::WeakPtr<ThreadProfiler> thread_profiler,
StackSamplingProfiler::CallStackProfile profile) { metrics::SampledProfile profile) {
receiver_callback.Run(std::move(profile)); receiver_callback.Run(std::move(profile));
owning_thread_task_runner->PostTask( owning_thread_task_runner->PostTask(
FROM_HERE, base::BindOnce(&ThreadProfiler::ScheduleNextPeriodicCollection, FROM_HERE, base::BindOnce(&ThreadProfiler::ScheduleNextPeriodicCollection,
...@@ -282,8 +281,9 @@ void ThreadProfiler::StartPeriodicSamplingCollection() { ...@@ -282,8 +281,9 @@ void ThreadProfiler::StartPeriodicSamplingCollection() {
// NB: Destroys the previous profiler as side effect. // NB: Destroys the previous profiler as side effect.
auto profile_builder = std::make_unique<CallStackProfileBuilder>( auto profile_builder = std::make_unique<CallStackProfileBuilder>(
BindRepeating(&ThreadProfiler::ReceivePeriodicProfile, BindRepeating(&ThreadProfiler::ReceivePeriodicProfile,
GetReceiverCallback(periodic_profile_params_), GetReceiverCallback(), owning_thread_task_runner_,
owning_thread_task_runner_, weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()),
periodic_profile_params_);
periodic_profiler_ = std::make_unique<StackSamplingProfiler>( periodic_profiler_ = std::make_unique<StackSamplingProfiler>(
base::PlatformThread::CurrentId(), kSamplingParams, base::PlatformThread::CurrentId(), kSamplingParams,
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/call_stack_profile_params.h" #include "components/metrics/call_stack_profile_params.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace service_manager { namespace service_manager {
class Connector; class Connector;
...@@ -93,8 +94,7 @@ class ThreadProfiler { ...@@ -93,8 +94,7 @@ class ThreadProfiler {
scoped_refptr<base::SingleThreadTaskRunner>()); scoped_refptr<base::SingleThreadTaskRunner>());
// Gets the completed callback for the ultimate receiver of the profile. // Gets the completed callback for the ultimate receiver of the profile.
metrics::CallStackProfileBuilder::CompletedCallback GetReceiverCallback( metrics::CallStackProfileBuilder::CompletedCallback GetReceiverCallback();
const metrics::CallStackProfileParams& profile_params);
// Receives |profile| from the metrics::CallStackProfileBuilder and forwards // Receives |profile| from the metrics::CallStackProfileBuilder and forwards
// it on to the original |receiver_callback|. Note that we must obtain and // it on to the original |receiver_callback|. Note that we must obtain and
...@@ -105,13 +105,13 @@ class ThreadProfiler { ...@@ -105,13 +105,13 @@ class ThreadProfiler {
static void ReceiveStartupProfile( static void ReceiveStartupProfile(
const metrics::CallStackProfileBuilder::CompletedCallback& const metrics::CallStackProfileBuilder::CompletedCallback&
receiver_callback, receiver_callback,
base::StackSamplingProfiler::CallStackProfile profile); metrics::SampledProfile profile);
static void ReceivePeriodicProfile( static void ReceivePeriodicProfile(
const metrics::CallStackProfileBuilder::CompletedCallback& const metrics::CallStackProfileBuilder::CompletedCallback&
receiver_callback, receiver_callback,
scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner, scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner,
base::WeakPtr<ThreadProfiler> thread_profiler, base::WeakPtr<ThreadProfiler> thread_profiler,
base::StackSamplingProfiler::CallStackProfile profile); metrics::SampledProfile profile);
// Posts a delayed task to start the next periodic sampling collection. // Posts a delayed task to start the next periodic sampling collection.
void ScheduleNextPeriodicCollection(); void ScheduleNextPeriodicCollection();
......
...@@ -262,10 +262,13 @@ source_set("call_stack_profile") { ...@@ -262,10 +262,13 @@ source_set("call_stack_profile") {
"call_stack_profile_builder.cc", "call_stack_profile_builder.cc",
"call_stack_profile_builder.h", "call_stack_profile_builder.h",
"call_stack_profile_params.h", "call_stack_profile_params.h",
"call_stack_profile_proto_encoder.cc",
"call_stack_profile_proto_encoder.h",
] ]
deps = [ deps = [
"//base:base", "//base:base",
"//third_party/metrics_proto",
] ]
} }
...@@ -277,6 +280,7 @@ source_set("call_stacks") { ...@@ -277,6 +280,7 @@ source_set("call_stacks") {
deps = [ deps = [
":metrics", ":metrics",
"//components/metrics/public/interfaces:call_stack_mojo_bindings", "//components/metrics/public/interfaces:call_stack_mojo_bindings",
"//third_party/metrics_proto",
] ]
} }
...@@ -289,6 +293,7 @@ source_set("child_call_stacks") { ...@@ -289,6 +293,7 @@ source_set("child_call_stacks") {
":call_stack_profile", ":call_stack_profile",
"//components/metrics/public/interfaces:call_stack_mojo_bindings", "//components/metrics/public/interfaces:call_stack_mojo_bindings",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
"//third_party/metrics_proto",
] ]
} }
...@@ -332,6 +337,7 @@ source_set("unit_tests") { ...@@ -332,6 +337,7 @@ source_set("unit_tests") {
sources = [ sources = [
"call_stack_profile_builder_unittest.cc", "call_stack_profile_builder_unittest.cc",
"call_stack_profile_metrics_provider_unittest.cc", "call_stack_profile_metrics_provider_unittest.cc",
"call_stack_profile_proto_encoder_unittest.cc",
"child_call_stack_profile_collector_unittest.cc", "child_call_stack_profile_collector_unittest.cc",
"cloned_install_detector_unittest.cc", "cloned_install_detector_unittest.cc",
"component_metrics_provider_unittest.cc", "component_metrics_provider_unittest.cc",
...@@ -383,6 +389,7 @@ source_set("unit_tests") { ...@@ -383,6 +389,7 @@ source_set("unit_tests") {
"//services/network/public/cpp:cpp", "//services/network/public/cpp:cpp",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
"//testing/gtest", "//testing/gtest",
"//third_party/metrics_proto",
"//third_party/zlib/google:compression_utils", "//third_party/zlib/google:compression_utils",
"//ui/gfx/geometry", "//ui/gfx/geometry",
] ]
......
...@@ -5,9 +5,10 @@ ...@@ -5,9 +5,10 @@
#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_builder.h"
#include <utility> #include <utility>
#include <vector>
#include "base/atomicops.h" #include "base/atomicops.h"
#include "base/logging.h" #include "components/metrics/call_stack_profile_proto_encoder.h"
using StackSamplingProfiler = base::StackSamplingProfiler; using StackSamplingProfiler = base::StackSamplingProfiler;
...@@ -41,8 +42,9 @@ void ChangeAtomicFlags(base::subtle::Atomic32* flags, ...@@ -41,8 +42,9 @@ void ChangeAtomicFlags(base::subtle::Atomic32* flags,
} // namespace } // namespace
CallStackProfileBuilder::CallStackProfileBuilder( CallStackProfileBuilder::CallStackProfileBuilder(
const CompletedCallback& callback) const CompletedCallback& callback,
: callback_(callback) {} const CallStackProfileParams& profile_params)
: callback_(callback), profile_params_(profile_params) {}
CallStackProfileBuilder::~CallStackProfileBuilder() = default; CallStackProfileBuilder::~CallStackProfileBuilder() = default;
...@@ -89,8 +91,20 @@ void CallStackProfileBuilder::OnProfileCompleted( ...@@ -89,8 +91,20 @@ void CallStackProfileBuilder::OnProfileCompleted(
profile_.profile_duration = profile_duration; profile_.profile_duration = profile_duration;
profile_.sampling_period = sampling_period; profile_.sampling_period = sampling_period;
// Run the associated callback, passing the collected profile. // TODO(chengx): build the metrics.SampledProfile protocol message
callback_.Run(std::move(profile_)); // incrementally.
SampledProfile sampled_profile;
sampled_profile.set_process(
ToExecutionContextProcess(profile_params_.process));
sampled_profile.set_thread(ToExecutionContextThread(profile_params_.thread));
sampled_profile.set_trigger_event(
ToSampledProfileTriggerEvent(profile_params_.trigger));
CopyProfileToProto(profile_, profile_params_.ordering_spec,
sampled_profile.mutable_call_stack_profile());
// Run the associated callback, passing the protocol message which encodes the
// collected profile.
callback_.Run(sampled_profile);
} }
// static // static
......
...@@ -9,23 +9,42 @@ ...@@ -9,23 +9,42 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/profiler/stack_sampling_profiler.h" #include "base/profiler/stack_sampling_profiler.h"
#include "components/metrics/call_stack_profile_params.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace metrics { namespace metrics {
// CallStackProfileBuilder builds a CallStackProfile from the collected sampling // CallStackProfileBuilder builds a CallStackProfile from the collected sampling
// data. // data.
// //
// The results of the profile building -- a CallStackProfile, is passed to the // The results of the profile building -- a CallStackProfile, is encoded to
// completed callback. A CallStackProfile contains a set of Samples and // metrics.SampledProfile protocol message. The message is then passed to the
// Modules, and other sampling information. One Sample corresponds to a single // completed callback. A CallStackProfile contains a set of Samples and Modules,
// recorded stack, and the Modules record those modules associated with the // and other sampling information. One Sample corresponds to a single recorded
// recorded stack frames. // stack, and the Modules record those modules associated with the recorded
// stack frames.
class CallStackProfileBuilder class CallStackProfileBuilder
: public base::StackSamplingProfiler::ProfileBuilder { : public base::StackSamplingProfiler::ProfileBuilder {
public: public:
// The callback type used to collect a completed profile. The passed // These milestones of a process lifetime can be passed as process "mile-
// CallStackProfile is move-only. Other threads, including the UI thread, may // stones" to CallStackProfileBuilder::SetProcessMilestone(). Be sure to
// block on callback completion so this should run as quickly as possible. // update the translation constants at the top of the .cc file when this is
// changed.
enum Milestones : int {
MAIN_LOOP_START,
MAIN_NAVIGATION_START,
MAIN_NAVIGATION_FINISHED,
FIRST_NONEMPTY_PAINT,
SHUTDOWN_START,
MILESTONES_MAX_VALUE
};
// The callback type used to collect a metrics.SampledProfile protocol
// message. The passed SampledProfile 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 // IMPORTANT NOTE: The callback is invoked on a thread the profiler
// constructs, rather than on the thread used to construct the profiler, and // constructs, rather than on the thread used to construct the profiler, and
...@@ -33,10 +52,10 @@ class CallStackProfileBuilder ...@@ -33,10 +52,10 @@ class CallStackProfileBuilder
// loops that create CallStackProfileBuilders, posting a task to the 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 // loop with the moved (i.e. std::move) profile is the thread-safe callback
// implementation. // implementation.
using CompletedCallback = using CompletedCallback = base::RepeatingCallback<void(SampledProfile)>;
base::Callback<void(base::StackSamplingProfiler::CallStackProfile)>;
CallStackProfileBuilder(const CompletedCallback& callback); CallStackProfileBuilder(const CompletedCallback& callback,
const CallStackProfileParams& profile_params);
~CallStackProfileBuilder() override; ~CallStackProfileBuilder() override;
...@@ -68,6 +87,9 @@ class CallStackProfileBuilder ...@@ -68,6 +87,9 @@ class CallStackProfileBuilder
// Callback made when sampling a profile completes. // Callback made when sampling a profile completes.
const CompletedCallback callback_; const CompletedCallback callback_;
// The parameters associated with the sampled profile.
const CallStackProfileParams profile_params_;
DISALLOW_COPY_AND_ASSIGN(CallStackProfileBuilder); DISALLOW_COPY_AND_ASSIGN(CallStackProfileBuilder);
}; };
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <utility> #include <utility>
#include "components/metrics/call_stack_profile_metrics_provider.h" #include "components/metrics/call_stack_profile_metrics_provider.h"
#include "mojo/public/cpp/bindings/interface_request.h" #include "components/metrics/call_stack_profile_proto_encoder.h"
#include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/bindings/strong_binding.h"
namespace metrics { namespace metrics {
...@@ -28,15 +28,13 @@ void CallStackProfileCollector::Create( ...@@ -28,15 +28,13 @@ void CallStackProfileCollector::Create(
std::move(request)); std::move(request));
} }
void CallStackProfileCollector::Collect(const CallStackProfileParams& params, void CallStackProfileCollector::Collect(base::TimeTicks start_timestamp,
base::TimeTicks start_timestamp, SampledProfile profile) {
CallStackProfile profile) { if (profile.process() != ToExecutionContextProcess(expected_process_))
if (params.process != expected_process_)
return; return;
CallStackProfileParams params_copy = params; CallStackProfileMetricsProvider::ReceiveCompletedProfile(start_timestamp,
CallStackProfileMetricsProvider::ReceiveCompletedProfile( std::move(profile));
params_copy, start_timestamp, std::move(profile));
} }
} // namespace metrics } // namespace metrics
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
#define COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_ #define COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
#include "base/macros.h" #include "base/macros.h"
#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h" #include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace metrics { namespace metrics {
class CallStackProfileCollector : public mojom::CallStackProfileCollector { class CallStackProfileCollector : public mojom::CallStackProfileCollector {
public: public:
using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
explicit CallStackProfileCollector( explicit CallStackProfileCollector(
CallStackProfileParams::Process expected_process); CallStackProfileParams::Process expected_process);
~CallStackProfileCollector() override; ~CallStackProfileCollector() override;
...@@ -23,9 +23,8 @@ class CallStackProfileCollector : public mojom::CallStackProfileCollector { ...@@ -23,9 +23,8 @@ class CallStackProfileCollector : public mojom::CallStackProfileCollector {
mojom::CallStackProfileCollectorRequest request); mojom::CallStackProfileCollectorRequest request);
// mojom::CallStackProfileCollector: // mojom::CallStackProfileCollector:
void Collect(const CallStackProfileParams& params, void Collect(base::TimeTicks start_timestamp,
base::TimeTicks start_timestamp, SampledProfile profile) override;
CallStackProfile profile) override;
private: private:
// Profile params are validated to come from this process. Profiles with a // Profile params are validated to come from this process. Profiles with a
......
...@@ -7,11 +7,10 @@ ...@@ -7,11 +7,10 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/time/time.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/metrics_provider.h" #include "components/metrics/metrics_provider.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace metrics { namespace metrics {
...@@ -20,21 +19,6 @@ class ChromeUserMetricsExtension; ...@@ -20,21 +19,6 @@ class ChromeUserMetricsExtension;
// Performs metrics logging for the stack sampling profiler. // Performs metrics logging for the stack sampling profiler.
class CallStackProfileMetricsProvider : public MetricsProvider { class CallStackProfileMetricsProvider : public MetricsProvider {
public: public:
// These milestones of a process lifetime can be passed as process "mile-
// 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,
MAIN_NAVIGATION_FINISHED,
FIRST_NONEMPTY_PAINT,
SHUTDOWN_START,
MILESTONES_MAX_VALUE
};
CallStackProfileMetricsProvider(); CallStackProfileMetricsProvider();
~CallStackProfileMetricsProvider() override; ~CallStackProfileMetricsProvider() override;
...@@ -43,16 +27,14 @@ class CallStackProfileMetricsProvider : public MetricsProvider { ...@@ -43,16 +27,14 @@ class CallStackProfileMetricsProvider : public MetricsProvider {
// immediately passed to the CallStackProfileBuilder, and should not be // immediately passed to the CallStackProfileBuilder, and should not be
// reused. // reused.
static CallStackProfileBuilder::CompletedCallback static CallStackProfileBuilder::CompletedCallback
GetProfilerCallbackForBrowserProcess(const CallStackProfileParams& params); GetProfilerCallbackForBrowserProcess();
// Provides completed stack profile 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 // when receiving profiles over IPC. In-process StackSamplingProfiler users
// should instead use a variant of GetProfilerCallback*(). |profile| is not // should instead use a variant of GetProfilerCallback*(). |profile| is not
// const& because it must be passed with std::move. // const& because it must be passed with std::move.
static void ReceiveCompletedProfile( static void ReceiveCompletedProfile(base::TimeTicks profile_start_time,
const CallStackProfileParams& params, SampledProfile profile);
base::TimeTicks profile_start_time,
base::StackSamplingProfiler::CallStackProfile profile);
// MetricsProvider: // MetricsProvider:
void OnRecordingEnabled() override; void OnRecordingEnabled() override;
......
// 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_proto_encoder.h"
#include <stddef.h>
#include <cstring>
#include <map>
#include <string>
#include <utility>
#include "base/logging.h"
#include "base/metrics/metrics_hashes.h"
#include "base/stl_util.h"
#include "components/metrics/call_stack_profile_builder.h"
namespace metrics {
namespace {
// 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
// with the protobuf -- even if there are ever more than 32 defined proto
// values, though never more than 32 could be in-use in a given C++ version
// of the code.
const ProcessPhase kProtoPhases[CallStackProfileBuilder::MILESTONES_MAX_VALUE] =
{
ProcessPhase::MAIN_LOOP_START,
ProcessPhase::MAIN_NAVIGATION_START,
ProcessPhase::MAIN_NAVIGATION_FINISHED,
ProcessPhase::FIRST_NONEMPTY_PAINT,
ProcessPhase::SHUTDOWN_START,
};
} // namespace
uint64_t HashModuleFilename(const base::FilePath& filename) {
const base::FilePath::StringType basename = filename.BaseName().value();
// Copy the bytes in basename into a string buffer.
size_t basename_length_in_bytes =
basename.size() * sizeof(base::FilePath::CharType);
std::string name_bytes(basename_length_in_bytes, '\0');
memcpy(&name_bytes[0], &basename[0], basename_length_in_bytes);
return base::HashMetricName(name_bytes);
}
void CopySampleToProto(
const base::StackSamplingProfiler::Sample& sample,
const std::vector<base::StackSamplingProfiler::Module>& modules,
CallStackProfile::Sample* proto_sample) {
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 == base::kUnknownModuleIndex)
continue;
int64_t module_offset =
reinterpret_cast<const char*>(frame.instruction_pointer) -
reinterpret_cast<const char*>(modules[frame.module_index].base_address);
DCHECK_GE(module_offset, 0);
entry->set_address(static_cast<uint64_t>(module_offset));
entry->set_module_id_index(frame.module_index);
}
}
void CopyAnnotationsToProto(uint32_t new_milestones,
CallStackProfile::Sample* sample_proto) {
for (size_t bit = 0; new_milestones != 0 && bit < sizeof(new_milestones) * 8;
++bit) {
const uint32_t flag = 1U << bit;
if (new_milestones & flag) {
if (bit >= base::size(kProtoPhases)) {
NOTREACHED();
continue;
}
sample_proto->add_process_phase(kProtoPhases[bit]);
new_milestones ^= flag; // Bit is set so XOR will clear it.
}
}
}
void CopyProfileToProto(
const base::StackSamplingProfiler::CallStackProfile& profile,
CallStackProfileParams::SampleOrderingSpec ordering_spec,
CallStackProfile* proto_profile) {
if (profile.samples.empty())
return;
const bool preserve_order =
ordering_spec == CallStackProfileParams::PRESERVE_ORDER;
std::map<base::StackSamplingProfiler::Sample, int> sample_index;
uint32_t milestones = 0;
for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
int existing_sample_index = -1;
if (preserve_order) {
// Collapse sample with the previous one if they match. Samples match
// if the frame and all annotations are the same.
if (proto_profile->sample_size() > 0 && *it == *(it - 1))
existing_sample_index = proto_profile->sample_size() - 1;
} else {
auto location = sample_index.find(*it);
if (location != sample_index.end())
existing_sample_index = location->second;
}
if (existing_sample_index != -1) {
CallStackProfile::Sample* sample_proto =
proto_profile->mutable_sample()->Mutable(existing_sample_index);
sample_proto->set_count(sample_proto->count() + 1);
continue;
}
CallStackProfile::Sample* sample_proto = proto_profile->add_sample();
CopySampleToProto(*it, profile.modules, sample_proto);
sample_proto->set_count(1);
CopyAnnotationsToProto(it->process_milestones & ~milestones, sample_proto);
milestones = it->process_milestones;
if (!preserve_order) {
sample_index.insert(std::make_pair(
*it, static_cast<int>(proto_profile->sample_size()) - 1));
}
}
for (const auto& module : profile.modules) {
CallStackProfile::ModuleIdentifier* module_id =
proto_profile->add_module_id();
module_id->set_build_id(module.id);
module_id->set_name_md5_prefix(HashModuleFilename(module.filename));
}
proto_profile->set_profile_duration_ms(
profile.profile_duration.InMilliseconds());
proto_profile->set_sampling_period_ms(
profile.sampling_period.InMilliseconds());
}
Process ToExecutionContextProcess(CallStackProfileParams::Process process) {
switch (process) {
case CallStackProfileParams::UNKNOWN_PROCESS:
return UNKNOWN_PROCESS;
case CallStackProfileParams::BROWSER_PROCESS:
return BROWSER_PROCESS;
case CallStackProfileParams::RENDERER_PROCESS:
return RENDERER_PROCESS;
case CallStackProfileParams::GPU_PROCESS:
return GPU_PROCESS;
case CallStackProfileParams::UTILITY_PROCESS:
return UTILITY_PROCESS;
case CallStackProfileParams::ZYGOTE_PROCESS:
return ZYGOTE_PROCESS;
case CallStackProfileParams::SANDBOX_HELPER_PROCESS:
return SANDBOX_HELPER_PROCESS;
case CallStackProfileParams::PPAPI_PLUGIN_PROCESS:
return PPAPI_PLUGIN_PROCESS;
case CallStackProfileParams::PPAPI_BROKER_PROCESS:
return PPAPI_BROKER_PROCESS;
}
NOTREACHED();
return UNKNOWN_PROCESS;
}
Thread ToExecutionContextThread(CallStackProfileParams::Thread thread) {
switch (thread) {
case CallStackProfileParams::UNKNOWN_THREAD:
return UNKNOWN_THREAD;
case CallStackProfileParams::MAIN_THREAD:
return MAIN_THREAD;
case CallStackProfileParams::IO_THREAD:
return IO_THREAD;
case CallStackProfileParams::COMPOSITOR_THREAD:
return COMPOSITOR_THREAD;
}
NOTREACHED();
return UNKNOWN_THREAD;
}
SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
CallStackProfileParams::Trigger trigger) {
switch (trigger) {
case CallStackProfileParams::UNKNOWN:
return SampledProfile::UNKNOWN_TRIGGER_EVENT;
case CallStackProfileParams::PROCESS_STARTUP:
return SampledProfile::PROCESS_STARTUP;
case CallStackProfileParams::JANKY_TASK:
return SampledProfile::JANKY_TASK;
case CallStackProfileParams::THREAD_HUNG:
return SampledProfile::THREAD_HUNG;
case CallStackProfileParams::PERIODIC_COLLECTION:
return SampledProfile::PERIODIC_COLLECTION;
}
NOTREACHED();
return SampledProfile::UNKNOWN_TRIGGER_EVENT;
}
} // namespace metrics
// 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_PROTO_ENCODER_H_
#define COMPONENTS_METRICS_CALL_STACK_PROFILE_PROTO_ENCODER_H_
#include <vector>
#include "base/files/file_path.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "components/metrics/call_stack_profile_params.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace metrics {
// These functions are used to encode protobufs.
// The protobuf expects the MD5 checksum prefix of the module name.
uint64_t HashModuleFilename(const base::FilePath& filename);
// Transcode |sample| into |proto_sample|, using base addresses in |modules| to
// compute module instruction pointer offsets.
void CopySampleToProto(
const base::StackSamplingProfiler::Sample& sample,
const std::vector<base::StackSamplingProfiler::Module>& modules,
CallStackProfile::Sample* proto_sample);
// Transcode Sample annotations into protobuf fields. The C++ code uses a bit-
// field with each bit corresponding to an entry in an enumeration while the
// protobuf uses a repeated field of individual values. Conversion tables
// allow for arbitrary mapping, though no more than 32 in any given version
// of the code.
void CopyAnnotationsToProto(uint32_t new_milestones,
CallStackProfile::Sample* sample_proto);
// Transcode |profile| into |proto_profile|.
void CopyProfileToProto(
const base::StackSamplingProfiler::CallStackProfile& profile,
CallStackProfileParams::SampleOrderingSpec ordering_spec,
CallStackProfile* proto_profile);
// Translates CallStackProfileParams's process to the corresponding
// execution context Process.
Process ToExecutionContextProcess(CallStackProfileParams::Process process);
// Translates CallStackProfileParams's thread to the corresponding
// SampledProfile Thread.
Thread ToExecutionContextThread(CallStackProfileParams::Thread thread);
// Translates CallStackProfileParams's trigger to the corresponding
// SampledProfile TriggerEvent.
SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
CallStackProfileParams::Trigger trigger);
} // namespace metrics
#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_PROTO_ENCODER_H_
...@@ -7,11 +7,10 @@ ...@@ -7,11 +7,10 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "services/service_manager/public/cpp/interface_provider.h" #include "base/time/time.h"
namespace metrics { namespace metrics {
...@@ -20,12 +19,9 @@ ChildCallStackProfileCollector::ProfileState::ProfileState(ProfileState&&) = ...@@ -20,12 +19,9 @@ ChildCallStackProfileCollector::ProfileState::ProfileState(ProfileState&&) =
default; default;
ChildCallStackProfileCollector::ProfileState::ProfileState( ChildCallStackProfileCollector::ProfileState::ProfileState(
const CallStackProfileParams& params,
base::TimeTicks start_timestamp, base::TimeTicks start_timestamp,
base::StackSamplingProfiler::CallStackProfile profile) SampledProfile profile)
: params(params), : start_timestamp(start_timestamp), profile(std::move(profile)) {}
start_timestamp(start_timestamp),
profile(std::move(profile)) {}
ChildCallStackProfileCollector::ProfileState::~ProfileState() = default; ChildCallStackProfileCollector::ProfileState::~ProfileState() = default;
...@@ -40,11 +36,10 @@ ChildCallStackProfileCollector::~ChildCallStackProfileCollector() {} ...@@ -40,11 +36,10 @@ ChildCallStackProfileCollector::~ChildCallStackProfileCollector() {}
CallStackProfileBuilder::CompletedCallback CallStackProfileBuilder::CompletedCallback
ChildCallStackProfileCollector::GetProfilerCallback( ChildCallStackProfileCollector::GetProfilerCallback(
const CallStackProfileParams& params,
base::TimeTicks profile_start_time) { base::TimeTicks profile_start_time) {
return base::Bind(&ChildCallStackProfileCollector::Collect, return base::Bind(&ChildCallStackProfileCollector::Collect,
// This class has lazy instance lifetime. // This class has lazy instance lifetime.
base::Unretained(this), params, profile_start_time); base::Unretained(this), profile_start_time);
} }
void ChildCallStackProfileCollector::SetParentProfileCollector( void ChildCallStackProfileCollector::SetParentProfileCollector(
...@@ -60,26 +55,23 @@ void ChildCallStackProfileCollector::SetParentProfileCollector( ...@@ -60,26 +55,23 @@ void ChildCallStackProfileCollector::SetParentProfileCollector(
parent_collector_ = std::move(parent_collector); parent_collector_ = std::move(parent_collector);
if (parent_collector_) { if (parent_collector_) {
for (ProfileState& state : profiles_) { for (ProfileState& state : profiles_) {
parent_collector_->Collect(state.params, state.start_timestamp, parent_collector_->Collect(state.start_timestamp,
std::move(state.profile)); std::move(state.profile));
} }
} }
profiles_.clear(); profiles_.clear();
} }
void ChildCallStackProfileCollector::Collect( void ChildCallStackProfileCollector::Collect(base::TimeTicks start_timestamp,
const CallStackProfileParams& params, SampledProfile profile) {
base::TimeTicks start_timestamp,
CallStackProfile profile) {
// Impl function is used as it needs to PostTask() to itself on a different // Impl function is used as it needs to PostTask() to itself on a different
// thread - which only works with a void return value. // thread - which only works with a void return value.
CollectImpl(params, start_timestamp, std::move(profile)); CollectImpl(start_timestamp, std::move(profile));
} }
void ChildCallStackProfileCollector::CollectImpl( void ChildCallStackProfileCollector::CollectImpl(
const CallStackProfileParams& params,
base::TimeTicks start_timestamp, base::TimeTicks start_timestamp,
CallStackProfile profile) { SampledProfile profile) {
base::AutoLock alock(lock_); base::AutoLock alock(lock_);
if (task_runner_ && if (task_runner_ &&
// The profiler thread does not have a task runner. Attempting to // The profiler thread does not have a task runner. Attempting to
...@@ -90,16 +82,15 @@ void ChildCallStackProfileCollector::CollectImpl( ...@@ -90,16 +82,15 @@ void ChildCallStackProfileCollector::CollectImpl(
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ChildCallStackProfileCollector::CollectImpl, FROM_HERE, base::BindOnce(&ChildCallStackProfileCollector::CollectImpl,
// This class has lazy instance lifetime. // This class has lazy instance lifetime.
base::Unretained(this), params, base::Unretained(this), start_timestamp,
start_timestamp, std::move(profile))); std::move(profile)));
return; return;
} }
if (parent_collector_) { if (parent_collector_) {
parent_collector_->Collect(params, start_timestamp, std::move(profile)); parent_collector_->Collect(start_timestamp, std::move(profile));
} else if (retain_profiles_) { } else if (retain_profiles_) {
profiles_.push_back( profiles_.push_back(ProfileState(start_timestamp, std::move(profile)));
ProfileState(params, start_timestamp, std::move(profile)));
} }
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h" #include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace service_manager { namespace service_manager {
class InterfaceProvider; class InterfaceProvider;
...@@ -56,7 +57,6 @@ class ChildCallStackProfileCollector { ...@@ -56,7 +57,6 @@ class ChildCallStackProfileCollector {
// to the CallStackProfileBuilder, and should not be reused between // to the CallStackProfileBuilder, and should not be reused between
// CallStackProfileBuilders. This function may be called on any thread. // CallStackProfileBuilders. This function may be called on any thread.
CallStackProfileBuilder::CompletedCallback GetProfilerCallback( CallStackProfileBuilder::CompletedCallback GetProfilerCallback(
const CallStackProfileParams& params,
base::TimeTicks profile_start_time); base::TimeTicks profile_start_time);
// Sets the CallStackProfileCollector interface from |parent_collector|. This // Sets the CallStackProfileCollector interface from |parent_collector|. This
...@@ -74,32 +74,23 @@ class ChildCallStackProfileCollector { ...@@ -74,32 +74,23 @@ class ChildCallStackProfileCollector {
struct ProfileState { struct ProfileState {
ProfileState(); ProfileState();
ProfileState(ProfileState&&); ProfileState(ProfileState&&);
ProfileState(const CallStackProfileParams& params, ProfileState(base::TimeTicks start_timestamp, SampledProfile profile);
base::TimeTicks start_timestamp,
base::StackSamplingProfiler::CallStackProfile profile);
~ProfileState(); ~ProfileState();
ProfileState& operator=(ProfileState&&); ProfileState& operator=(ProfileState&&);
CallStackProfileParams params;
base::TimeTicks start_timestamp; base::TimeTicks start_timestamp;
// The sampled profile. // The sampled profile.
base::StackSamplingProfiler::CallStackProfile profile; SampledProfile profile;
private: private:
DISALLOW_COPY_AND_ASSIGN(ProfileState); DISALLOW_COPY_AND_ASSIGN(ProfileState);
}; };
using CallStackProfile = base::StackSamplingProfiler::CallStackProfile; void Collect(base::TimeTicks start_timestamp, SampledProfile profile);
void Collect(const CallStackProfileParams& params, void CollectImpl(base::TimeTicks start_timestamp, SampledProfile profile);
base::TimeTicks start_timestamp,
CallStackProfile profile);
void CollectImpl(const CallStackProfileParams& params,
base::TimeTicks start_timestamp,
CallStackProfile profile);
// This object may be accessed on any thread, including the profiler // 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 // thread. The expected use case for the object is to be created and have
......
...@@ -11,10 +11,7 @@ ...@@ -11,10 +11,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "components/metrics/call_stack_profile_params.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace metrics { namespace metrics {
...@@ -23,17 +20,14 @@ class ChildCallStackProfileCollectorTest : public testing::Test { ...@@ -23,17 +20,14 @@ class ChildCallStackProfileCollectorTest : public testing::Test {
protected: protected:
class Receiver : public mojom::CallStackProfileCollector { class Receiver : public mojom::CallStackProfileCollector {
public: public:
using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
explicit Receiver(mojom::CallStackProfileCollectorRequest request) explicit Receiver(mojom::CallStackProfileCollectorRequest request)
: binding_(this, std::move(request)) {} : binding_(this, std::move(request)) {}
~Receiver() override {} ~Receiver() override {}
void Collect(const CallStackProfileParams& params, void Collect(base::TimeTicks start_timestamp,
base::TimeTicks start_timestamp, SampledProfile profile) override {
CallStackProfile profile) override {
this->profiles.push_back(ChildCallStackProfileCollector::ProfileState( this->profiles.push_back(ChildCallStackProfileCollector::ProfileState(
params, start_timestamp, std::move(profile))); start_timestamp, std::move(profile)));
} }
std::vector<ChildCallStackProfileCollector::ProfileState> profiles; std::vector<ChildCallStackProfileCollector::ProfileState> profiles;
...@@ -47,10 +41,9 @@ class ChildCallStackProfileCollectorTest : public testing::Test { ...@@ -47,10 +41,9 @@ class ChildCallStackProfileCollectorTest : public testing::Test {
ChildCallStackProfileCollectorTest() ChildCallStackProfileCollectorTest()
: receiver_impl_(new Receiver(MakeRequest(&receiver_))) {} : receiver_impl_(new Receiver(MakeRequest(&receiver_))) {}
void CollectEmptyProfile(const CallStackProfileParams& params) { void CollectEmptyProfile() {
base::StackSamplingProfiler::CallStackProfile profile; child_collector_.GetProfilerCallback(base::TimeTicks::Now())
child_collector_.GetProfilerCallback(params, base::TimeTicks::Now()) .Run(SampledProfile());
.Run(std::move(profile));
} }
const std::vector<ChildCallStackProfileCollector::ProfileState>& profiles() const std::vector<ChildCallStackProfileCollector::ProfileState>& profiles()
...@@ -72,17 +65,8 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) { ...@@ -72,17 +65,8 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) {
EXPECT_EQ(0u, profiles().size()); EXPECT_EQ(0u, profiles().size());
// Add a profile before providing the interface. // Add a profile before providing the interface.
CollectEmptyProfile(CallStackProfileParams( CollectEmptyProfile();
CallStackProfileParams::BROWSER_PROCESS,
CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::JANKY_TASK,
CallStackProfileParams::PRESERVE_ORDER));
ASSERT_EQ(1u, profiles().size()); ASSERT_EQ(1u, profiles().size());
EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS,
profiles()[0].params.process);
EXPECT_EQ(CallStackProfileParams::MAIN_THREAD, profiles()[0].params.thread);
EXPECT_EQ(CallStackProfileParams::JANKY_TASK, profiles()[0].params.trigger);
EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
profiles()[0].params.ordering_spec);
base::TimeTicks start_timestamp = profiles()[0].start_timestamp; base::TimeTicks start_timestamp = profiles()[0].start_timestamp;
EXPECT_GE(base::TimeDelta::FromMilliseconds(10), EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
base::TimeTicks::Now() - start_timestamp); base::TimeTicks::Now() - start_timestamp);
...@@ -92,29 +76,14 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) { ...@@ -92,29 +76,14 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_EQ(0u, profiles().size()); EXPECT_EQ(0u, profiles().size());
ASSERT_EQ(1u, receiver_impl_->profiles.size()); ASSERT_EQ(1u, receiver_impl_->profiles.size());
EXPECT_EQ(CallStackProfileParams::JANKY_TASK,
receiver_impl_->profiles[0].params.trigger);
EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
receiver_impl_->profiles[0].params.ordering_spec);
EXPECT_EQ(start_timestamp, receiver_impl_->profiles[0].start_timestamp); EXPECT_EQ(start_timestamp, receiver_impl_->profiles[0].start_timestamp);
// Add a profile after providing the interface. It should also be passed. // Add a profile after providing the interface. It should also be passed.
receiver_impl_->profiles.clear(); receiver_impl_->profiles.clear();
CollectEmptyProfile(CallStackProfileParams( CollectEmptyProfile();
CallStackProfileParams::GPU_PROCESS, CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::THREAD_HUNG,
CallStackProfileParams::PRESERVE_ORDER));
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_EQ(0u, profiles().size()); EXPECT_EQ(0u, profiles().size());
ASSERT_EQ(1u, receiver_impl_->profiles.size()); ASSERT_EQ(1u, receiver_impl_->profiles.size());
EXPECT_EQ(CallStackProfileParams::GPU_PROCESS,
receiver_impl_->profiles[0].params.process);
EXPECT_EQ(CallStackProfileParams::MAIN_THREAD,
receiver_impl_->profiles[0].params.thread);
EXPECT_EQ(CallStackProfileParams::THREAD_HUNG,
receiver_impl_->profiles[0].params.trigger);
EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
receiver_impl_->profiles[0].params.ordering_spec);
EXPECT_GE(base::TimeDelta::FromMilliseconds(10), EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
(base::TimeTicks::Now() - (base::TimeTicks::Now() -
receiver_impl_->profiles[0].start_timestamp)); receiver_impl_->profiles[0].start_timestamp));
...@@ -124,17 +93,8 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) { ...@@ -124,17 +93,8 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) {
EXPECT_EQ(0u, profiles().size()); EXPECT_EQ(0u, profiles().size());
// Add a profile before providing a null interface. // Add a profile before providing a null interface.
CollectEmptyProfile(CallStackProfileParams( CollectEmptyProfile();
CallStackProfileParams::BROWSER_PROCESS,
CallStackProfileParams::MAIN_THREAD, CallStackProfileParams::JANKY_TASK,
CallStackProfileParams::PRESERVE_ORDER));
ASSERT_EQ(1u, profiles().size()); ASSERT_EQ(1u, profiles().size());
EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS,
profiles()[0].params.process);
EXPECT_EQ(CallStackProfileParams::MAIN_THREAD, profiles()[0].params.thread);
EXPECT_EQ(CallStackProfileParams::JANKY_TASK, profiles()[0].params.trigger);
EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
profiles()[0].params.ordering_spec);
EXPECT_GE(base::TimeDelta::FromMilliseconds(10), EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
base::TimeTicks::Now() - profiles()[0].start_timestamp); base::TimeTicks::Now() - profiles()[0].start_timestamp);
...@@ -146,10 +106,7 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) { ...@@ -146,10 +106,7 @@ TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) {
// Add a profile after providing a null interface. They should also be // Add a profile after providing a null interface. They should also be
// flushed. // flushed.
CollectEmptyProfile(CallStackProfileParams( CollectEmptyProfile();
CallStackProfileParams::GPU_PROCESS, CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::THREAD_HUNG,
CallStackProfileParams::PRESERVE_ORDER));
EXPECT_EQ(0u, profiles().size()); EXPECT_EQ(0u, profiles().size());
} }
......
...@@ -15,5 +15,6 @@ source_set("call_stack_unit_tests") { ...@@ -15,5 +15,6 @@ source_set("call_stack_unit_tests") {
"//components/metrics/public/interfaces:call_stack_mojo_test_bindings", "//components/metrics/public/interfaces:call_stack_mojo_test_bindings",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//testing/gtest", "//testing/gtest",
"//third_party/metrics_proto",
] ]
} }
...@@ -4,24 +4,11 @@ ...@@ -4,24 +4,11 @@
mojom = mojom =
"//components/metrics/public/interfaces/call_stack_profile_collector.mojom" "//components/metrics/public/interfaces/call_stack_profile_collector.mojom"
public_headers = [ public_headers = [ "//third_party/metrics_proto/sampled_profile.pb.h" ]
"//base/profiler/stack_sampling_profiler.h",
"//components/metrics/call_stack_profile_params.h",
]
traits_headers = traits_headers =
[ "//components/metrics/public/cpp/call_stack_profile_struct_traits.h" ] [ "//components/metrics/public/cpp/call_stack_profile_struct_traits.h" ]
deps = [ deps = [
"//base", "//third_party/metrics_proto",
"//components/metrics:call_stack_profile",
]
type_mappings = [
"metrics.mojom.CallStackModule=base::StackSamplingProfiler::Module",
"metrics.mojom.CallStackFrame=base::StackSamplingProfiler::Frame",
"metrics.mojom.CallStackSample=base::StackSamplingProfiler::Sample[move_only]",
"metrics.mojom.CallStackProfile=base::StackSamplingProfiler::CallStackProfile[move_only]",
"metrics.mojom.CallStackProfileParams=metrics::CallStackProfileParams",
"metrics.mojom.Process=metrics::CallStackProfileParams::Process",
"metrics.mojom.SampleOrderingSpec=metrics::CallStackProfileParams::SampleOrderingSpec",
"metrics.mojom.Thread=metrics::CallStackProfileParams::Thread",
"metrics.mojom.Trigger=metrics::CallStackProfileParams::Trigger",
] ]
type_mappings =
[ "metrics.mojom.SampledProfile=metrics::SampledProfile[move_only]" ]
# 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.
# This file is necessary because without it compiling
# call_stack_profile_struct_traits_unittest produces error below:
# "gen\third_party/metrics_proto/sampled_profile.pb.h(9,10): fatal error:
# 'google/protobuf/stubs/common.h' file not found".
mojom = "//components/metrics/public/interfaces/call_stack_profile_collector_test.mojom"
public_headers = [ "//third_party/metrics_proto/sampled_profile.pb.h" ]
traits_headers =
[ "//components/metrics/public/cpp/call_stack_profile_struct_traits.h" ]
deps = [
"//third_party/metrics_proto",
]
type_mappings =
[ "metrics.mojom.SampledProfile=metrics::SampledProfile[move_only]" ]
...@@ -2,4 +2,7 @@ ...@@ -2,4 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
typemaps = [ "//components/metrics/public/cpp/call_stack_profile.typemap" ] typemaps = [
"//components/metrics/public/cpp/call_stack_profile.typemap",
"//components/metrics/public/cpp/call_stack_profile_unittest.typemap",
]
...@@ -4,75 +4,18 @@ ...@@ -4,75 +4,18 @@
module metrics.mojom; module metrics.mojom;
import "mojo/public/mojom/base/file_path.mojom";
import "mojo/public/mojom/base/time.mojom"; import "mojo/public/mojom/base/time.mojom";
// These structs mirror the corresponding types in base::StackSamplingProfiler. // |contents| is a serialized protobuf from
// src/third_party/metrics_proto/sampled_profile.proto.
struct CallStackModule { //
uint64 base_address; // We pass this state via serialized protobuf because that is the ultimate
string id; // metrics upload format.
mojo_base.mojom.FilePath filename; struct SampledProfile {
}; string contents;
struct CallStackFrame {
uint64 instruction_pointer;
uint64 module_index;
};
struct CallStackSample {
array<CallStackFrame> frames;
uint32 process_milestones;
};
struct CallStackProfile {
array<CallStackModule> modules;
array<CallStackSample> samples;
mojo_base.mojom.TimeDelta profile_duration;
mojo_base.mojom.TimeDelta sampling_period;
};
enum Process {
UNKNOWN_PROCESS,
BROWSER_PROCESS,
RENDERER_PROCESS,
GPU_PROCESS,
UTILITY_PROCESS,
ZYGOTE_PROCESS,
SANDBOX_HELPER_PROCESS,
PPAPI_PLUGIN_PROCESS,
PPAPI_BROKER_PROCESS,
};
enum Thread {
UNKNOWN_THREAD,
MAIN_THREAD,
IO_THREAD,
COMPOSITOR_THREAD,
};
enum Trigger {
UNKNOWN,
PROCESS_STARTUP,
JANKY_TASK,
THREAD_HUNG,
PERIODIC_COLLECTION,
};
enum SampleOrderingSpec {
MAY_SHUFFLE,
PRESERVE_ORDER,
};
struct CallStackProfileParams {
Process process;
Thread thread;
Trigger trigger;
SampleOrderingSpec ordering_spec;
}; };
interface CallStackProfileCollector { interface CallStackProfileCollector {
Collect(CallStackProfileParams params, Collect(mojo_base.mojom.TimeTicks start_timestamp,
mojo_base.mojom.TimeTicks start_timestamp, SampledProfile profile);
CallStackProfile profile);
}; };
...@@ -8,26 +8,5 @@ import "components/metrics/public/interfaces/call_stack_profile_collector.mojom" ...@@ -8,26 +8,5 @@ import "components/metrics/public/interfaces/call_stack_profile_collector.mojom"
interface CallStackProfileCollectorTest { interface CallStackProfileCollectorTest {
[Sync] [Sync]
BounceFrame(CallStackFrame in) => (CallStackFrame out); BounceSampledProfile(SampledProfile in) => (SampledProfile out);
[Sync]
BounceModule(CallStackModule in) => (CallStackModule out);
[Sync]
BounceProfile(CallStackProfile in) => (CallStackProfile out);
[Sync]
BounceProcess(Process in) => (Process out);
[Sync]
BounceThread(Thread in) => (Thread out);
[Sync]
BounceTrigger(Trigger in) => (Trigger out);
[Sync]
BounceSampleOrderingSpec(SampleOrderingSpec in) => (SampleOrderingSpec out);
[Sync]
BounceCallStackProfileParams(CallStackProfileParams in) => (CallStackProfileParams out);
}; };
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/metrics/call_stack_profile_builder.h" #include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/call_stack_profile_metrics_provider.h"
#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/startup_metric_utils/browser/pref_names.h" #include "components/startup_metric_utils/browser/pref_names.h"
...@@ -577,7 +576,7 @@ void RecordBrowserMainMessageLoopStart(base::TimeTicks ticks, ...@@ -577,7 +576,7 @@ void RecordBrowserMainMessageLoopStart(base::TimeTicks ticks,
// Record timing of the browser message-loop start time. // Record timing of the browser message-loop start time.
metrics::CallStackProfileBuilder::SetProcessMilestone( metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileMetricsProvider::MAIN_LOOP_START); metrics::CallStackProfileBuilder::MAIN_LOOP_START);
if (!is_first_run && !g_process_creation_ticks.is_null()) { if (!is_first_run && !g_process_creation_ticks.is_null()) {
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserMessageLoopStartTime", UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserMessageLoopStartTime",
...@@ -684,7 +683,7 @@ void RecordFirstWebContentsNonEmptyPaint( ...@@ -684,7 +683,7 @@ void RecordFirstWebContentsNonEmptyPaint(
return; return;
metrics::CallStackProfileBuilder::SetProcessMilestone( metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileMetricsProvider::FIRST_NONEMPTY_PAINT); metrics::CallStackProfileBuilder::FIRST_NONEMPTY_PAINT);
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.NonEmptyPaint2", UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.NonEmptyPaint2",
g_process_creation_ticks, now); g_process_creation_ticks, now);
...@@ -709,7 +708,7 @@ void RecordFirstWebContentsMainNavigationStart(base::TimeTicks ticks, ...@@ -709,7 +708,7 @@ void RecordFirstWebContentsMainNavigationStart(base::TimeTicks ticks,
return; return;
metrics::CallStackProfileBuilder::SetProcessMilestone( metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileMetricsProvider::MAIN_NAVIGATION_START); metrics::CallStackProfileBuilder::MAIN_NAVIGATION_START);
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, UMA_HISTOGRAM_LONG_TIMES_100,
"Startup.FirstWebContents.MainNavigationStart", g_process_creation_ticks, "Startup.FirstWebContents.MainNavigationStart", g_process_creation_ticks,
...@@ -740,7 +739,7 @@ void RecordFirstWebContentsMainNavigationFinished(base::TimeTicks ticks) { ...@@ -740,7 +739,7 @@ void RecordFirstWebContentsMainNavigationFinished(base::TimeTicks ticks) {
return; return;
metrics::CallStackProfileBuilder::SetProcessMilestone( metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileMetricsProvider::MAIN_NAVIGATION_FINISHED); metrics::CallStackProfileBuilder::MAIN_NAVIGATION_FINISHED);
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, UMA_HISTOGRAM_LONG_TIMES_100,
"Startup.FirstWebContents.MainNavigationFinished", "Startup.FirstWebContents.MainNavigationFinished",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment