Commit b2e858e5 authored by Xi Cheng's avatar Xi Cheng Committed by Commit Bot

Introduce new CallStackProfileBuilder using the new StackSample encoding

We deliberately leave out the process phase metadata information in the
StackSample encoding in this CL. Implementing that metadata support will
need to be done differently to make it extensible to general metadata.
We will implement it using follow-up CLs.

The old CallStackProfileBuilder using the legacy Sample encoding is
renamed to LegacyCallStackProfileBuilder. Related files are renamed
accordingly too.

Note that the old CallStackProfileBuilder is still used in production.

Bug: 851163, 804942
Change-Id: I235bd8cc839de4e663f1d4bd49aa24485649692a
Reviewed-on: https://chromium-review.googlesource.com/1205896Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Reviewed-by: default avatarSiddhartha S <ssid@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarAlexei Filippov <alph@chromium.org>
Reviewed-by: default avatarMike Wittman <wittman@chromium.org>
Commit-Queue: Xi Cheng <chengx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590465}
parent 2d01c9a0
......@@ -612,6 +612,8 @@ void StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(
SamplingThread::TestAPI::ShutdownAssumingIdle(simulate_intervening_start);
}
void StackSamplingProfiler::ProfileBuilder::RecordAnnotations() {}
StackSamplingProfiler::StackSamplingProfiler(
const SamplingParams& params,
std::unique_ptr<ProfileBuilder> profile_builder,
......
......@@ -124,7 +124,7 @@ class BASE_EXPORT StackSamplingProfiler {
// a mutex, including allocating memory (which includes LOG messages)
// because that mutex could be held by a stopped thread, thus resulting in
// deadlock.
virtual void RecordAnnotations() = 0;
virtual void RecordAnnotations();
// Records a new set of frames. Invoked when sampling a sample completes.
virtual void OnSampleCompleted(std::vector<Frame> frames) = 0;
......
......@@ -135,10 +135,10 @@
#include "components/language/core/browser/pref_names.h"
#include "components/language/core/common/language_experiments.h"
#include "components/language_usage_metrics/language_usage_metrics.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/expired_histogram_util.h"
#include "components/metrics/legacy_call_stack_profile_builder.h"
#include "components/metrics/metrics_reporting_default_state.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
......@@ -2120,8 +2120,8 @@ void ChromeBrowserMainParts::PostMainMessageLoopRun() {
}
void ChromeBrowserMainParts::PreShutdown() {
metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileBuilder::SHUTDOWN_START);
metrics::LegacyCallStackProfileBuilder::SetProcessMilestone(
metrics::LegacyCallStackProfileBuilder::SHUTDOWN_START);
}
void ChromeBrowserMainParts::PostDestroyThreads() {
......
......@@ -22,7 +22,7 @@ include_rules = [
"+components/metrics/call_stack_profile_metrics_provider.h",
"+components/metrics/call_stack_profile_params.h",
"+components/metrics/child_call_stack_profile_collector.h",
"+components/metrics/call_stack_profile_builder.h",
"+components/metrics/legacy_call_stack_profile_builder.h",
"+components/metrics/client_info.h",
"+components/metrics/metrics_pref_names.h",
"+components/nacl/common",
......
......@@ -15,7 +15,7 @@
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/post_task.h"
#include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/legacy_call_stack_profile_builder.h"
#include "content/public/common/content_switches.h"
namespace {
......@@ -104,7 +104,7 @@ void HeapProfilerController::RetrieveAndSendSnapshot() {
metrics::CallStackProfileParams::BROWSER_PROCESS,
metrics::CallStackProfileParams::UNKNOWN_THREAD,
metrics::CallStackProfileParams::PERIODIC_HEAP_COLLECTION);
metrics::CallStackProfileBuilder profile_builder(params);
metrics::LegacyCallStackProfileBuilder profile_builder(params);
for (const base::SamplingHeapProfiler::Sample& sample : samples) {
std::vector<base::StackSamplingProfiler::Frame> frames;
......
......@@ -8,7 +8,7 @@
#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
#include "base/test/bind_test_util.h"
#include "base/test/test_mock_time_task_runner.h"
#include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/legacy_call_stack_profile_builder.h"
#include "content/public/common/content_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
......@@ -21,7 +21,7 @@ TEST(HeapProfilerControllerTest, ProfileCollectionsScheduler) {
command_line->AppendSwitchASCII(switches::kSamplingHeapProfiler, "1");
int profiles_collected = 0;
metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
metrics::LegacyCallStackProfileBuilder::SetBrowserProcessReceiverCallback(
base::BindLambdaForTesting(
[&](base::TimeTicks time, metrics::SampledProfile profile) {
EXPECT_EQ(metrics::SampledProfile::PERIODIC_HEAP_COLLECTION,
......
......@@ -21,8 +21,8 @@
#include "services/service_manager/embedder/switches.h"
#include "services/service_manager/public/cpp/connector.h"
using CallStackProfileBuilder = metrics::CallStackProfileBuilder;
using CallStackProfileParams = metrics::CallStackProfileParams;
using LegacyCallStackProfileBuilder = metrics::LegacyCallStackProfileBuilder;
using StackSamplingProfiler = base::StackSamplingProfiler;
namespace {
......@@ -150,7 +150,8 @@ void ThreadProfiler::StartOnChildThread(CallStackProfileParams::Thread thread) {
void ThreadProfiler::SetBrowserProcessReceiverCallback(
const base::RepeatingCallback<void(base::TimeTicks,
metrics::SampledProfile)>& callback) {
metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(callback);
metrics::LegacyCallStackProfileBuilder::SetBrowserProcessReceiverCallback(
callback);
}
// static
......@@ -164,7 +165,7 @@ void ThreadProfiler::SetServiceManagerConnectorForChildProcess(
metrics::mojom::CallStackProfileCollectorPtr browser_interface;
connector->BindInterface(content::mojom::kBrowserServiceName,
&browser_interface);
CallStackProfileBuilder::SetParentProfileCollectorForChildProcess(
LegacyCallStackProfileBuilder::SetParentProfileCollectorForChildProcess(
std::move(browser_interface));
}
......@@ -197,9 +198,9 @@ ThreadProfiler::ThreadProfiler(
if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
return;
auto profile_builder = std::make_unique<CallStackProfileBuilder>(
CallStackProfileParams(GetProcess(), thread,
CallStackProfileParams::PROCESS_STARTUP));
auto profile_builder =
std::make_unique<LegacyCallStackProfileBuilder>(CallStackProfileParams(
GetProcess(), thread, CallStackProfileParams::PROCESS_STARTUP));
startup_profiler_ = std::make_unique<StackSamplingProfiler>(
base::PlatformThread::CurrentId(), kSamplingParams,
......@@ -244,7 +245,7 @@ void ThreadProfiler::ScheduleNextPeriodicCollection() {
void ThreadProfiler::StartPeriodicSamplingCollection() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// NB: Destroys the previous profiler as side effect.
auto profile_builder = std::make_unique<CallStackProfileBuilder>(
auto profile_builder = std::make_unique<LegacyCallStackProfileBuilder>(
periodic_profile_params_,
base::BindOnce(&ThreadProfiler::OnPeriodicCollectionCompleted,
owning_thread_task_runner_, weak_factory_.GetWeakPtr()));
......
......@@ -14,8 +14,8 @@
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/legacy_call_stack_profile_builder.h"
namespace service_manager {
class Connector;
......
......@@ -276,10 +276,12 @@ source_set("child_call_stack_profile_builder") {
public = [
"call_stack_profile_builder.h",
"child_call_stack_profile_collector.h",
"legacy_call_stack_profile_builder.h",
]
sources = [
"call_stack_profile_builder.cc",
"child_call_stack_profile_collector.cc",
"legacy_call_stack_profile_builder.cc",
]
public_deps = [
":call_stack_profile_params",
......@@ -370,6 +372,7 @@ source_set("unit_tests") {
"field_trials_provider_unittest.cc",
"file_metrics_provider_unittest.cc",
"histogram_encoder_unittest.cc",
"legacy_call_stack_profile_builder_unittest.cc",
"machine_id_provider_win_unittest.cc",
"metrics_log_manager_unittest.cc",
"metrics_log_store_unittest.cc",
......
......@@ -18,66 +18,14 @@
namespace metrics {
class SampledProfile;
// An instance of the class is meant to be passed to base::StackSamplingProfiler
// to collect profiles. The profiles collected are uploaded via the metrics log.
//
// This uses the new StackSample encoding rather than the legacy Sample
// encoding.
class CallStackProfileBuilder
: public base::StackSamplingProfiler::ProfileBuilder {
public:
// Frame represents an individual sampled stack frame with module information.
struct Frame {
Frame(uintptr_t instruction_pointer, size_t module_index);
~Frame();
// Default constructor to satisfy IPC macros. Do not use explicitly.
Frame();
// The sampled instruction pointer within the function.
uintptr_t instruction_pointer;
// Index of the module in the associated vector of mofules. We don't
// represent module state directly here to save space.
size_t module_index;
};
// Sample represents a set of stack frames with some extra information.
struct Sample {
Sample();
Sample(const Sample& sample);
~Sample();
// These constructors are used only during testing.
Sample(const Frame& frame);
Sample(const std::vector<Frame>& frames);
// The entire stack frame when the sample is taken.
std::vector<Frame> frames;
// A bit-field indicating which process milestones have passed. This can be
// used to tell where in the process lifetime the samples are taken. Just
// as a "lifetime" can only move forward, these bits mark the milestones of
// the processes life as they occur. Bits can be set but never reset. The
// actual definition of the individual bits is left to the user of this
// module.
uint32_t process_milestones = 0;
};
// 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
};
// |completed_callback| is made when sampling a profile completes. Other
// threads, including the UI thread, may block on callback completion so this
// should run as quickly as possible.
......@@ -92,7 +40,6 @@ class CallStackProfileBuilder
~CallStackProfileBuilder() override;
// base::StackSamplingProfiler::ProfileBuilder:
void RecordAnnotations() override;
void OnSampleCompleted(
std::vector<base::StackSamplingProfiler::Frame> frames) override;
void OnProfileCompleted(base::TimeDelta profile_duration,
......@@ -110,14 +57,6 @@ class CallStackProfileBuilder
const base::RepeatingCallback<void(base::TimeTicks, SampledProfile)>&
callback);
// 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);
// Sets the CallStackProfileCollector interface from |browser_interface|.
// This function must be called within child processes.
static void SetParentProfileCollectorForChildProcess(
......@@ -128,14 +67,18 @@ class CallStackProfileBuilder
virtual void PassProfilesToMetricsProvider(SampledProfile sampled_profile);
private:
// The collected stack samples in proto buffer message format.
CallStackProfile proto_profile_;
// The functor for Stack comparison.
struct StackComparer {
bool operator()(const CallStackProfile::Stack* stack1,
const CallStackProfile::Stack* stack2) const;
};
// The current sample being recorded.
Sample sample_;
// The SampledProfile protobuf message which contains the collected stack
// samples.
SampledProfile sampled_profile_;
// The indexes of samples, indexed by the sample.
std::map<Sample, int> sample_index_;
// The indexes of stacks, indexed by stack's address.
std::map<const CallStackProfile::Stack*, int, StackComparer> stack_index_;
// The indexes of modules, indexed by module's base_address.
std::map<uintptr_t, size_t> module_index_;
......@@ -143,15 +86,9 @@ class CallStackProfileBuilder
// The distinct modules in the current profile.
std::vector<base::ModuleCache::Module> modules_;
// The process milestones of a previous sample.
uint32_t milestones_ = 0;
// Callback made when sampling a profile completes.
base::OnceClosure completed_callback_;
// The parameters associated with the sampled profile.
const CallStackProfileParams profile_params_;
// The start time of a profile collection.
const base::TimeTicks profile_start_time_;
......
This diff is collapsed.
// 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_LEGACY_CALL_STACK_PROFILE_BUILDER_H_
#define COMPONENTS_METRICS_LEGACY_CALL_STACK_PROFILE_BUILDER_H_
#include <map>
#include <vector>
#include "base/callback.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "base/sampling_heap_profiler/module_cache.h"
#include "base/time/time.h"
#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/child_call_stack_profile_collector.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"
namespace metrics {
// An instance of the class is meant to be passed to base::StackSamplingProfiler
// to collect profiles. The profiles collected are uploaded via the metrics log.
//
// This uses the legacy Sample encoding rather than the new StackSample
// encoding.
class LegacyCallStackProfileBuilder
: public base::StackSamplingProfiler::ProfileBuilder {
public:
// Frame represents an individual sampled stack frame with module information.
struct Frame {
Frame(uintptr_t instruction_pointer, size_t module_index);
~Frame();
// Default constructor to satisfy IPC macros. Do not use explicitly.
Frame();
// The sampled instruction pointer within the function.
uintptr_t instruction_pointer;
// Index of the module in the associated vector of mofules. We don't
// represent module state directly here to save space.
size_t module_index;
};
// Sample represents a set of stack frames with some extra information.
struct Sample {
Sample();
Sample(const Sample& sample);
~Sample();
// These constructors are used only during testing.
Sample(const Frame& frame);
Sample(const std::vector<Frame>& frames);
// The entire stack frame when the sample is taken.
std::vector<Frame> frames;
// A bit-field indicating which process milestones have passed. This can be
// used to tell where in the process lifetime the samples are taken. Just
// as a "lifetime" can only move forward, these bits mark the milestones of
// the processes life as they occur. Bits can be set but never reset. The
// actual definition of the individual bits is left to the user of this
// module.
uint32_t process_milestones = 0;
};
// These milestones of a process lifetime can be passed as process "mile-
// stones" to LegacyCallStackProfileBuilder::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
};
// |completed_callback| is made when sampling a profile completes. 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.
explicit LegacyCallStackProfileBuilder(
const CallStackProfileParams& profile_params,
base::OnceClosure completed_callback = base::OnceClosure());
~LegacyCallStackProfileBuilder() override;
// base::StackSamplingProfiler::ProfileBuilder:
void RecordAnnotations() override;
void OnSampleCompleted(
std::vector<base::StackSamplingProfiler::Frame> frames) override;
void OnProfileCompleted(base::TimeDelta profile_duration,
base::TimeDelta sampling_period) override;
// The function is used by sampling heap profiler. Its samples already come
// with different counts.
void OnSampleCompleted(std::vector<base::StackSamplingProfiler::Frame> frames,
size_t count);
// Sets the callback to use for reporting browser process profiles. This
// indirection is required to avoid a dependency on unnecessary metrics code
// in child processes.
static void SetBrowserProcessReceiverCallback(
const base::RepeatingCallback<void(base::TimeTicks, SampledProfile)>&
callback);
// 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);
// Sets the CallStackProfileCollector interface from |browser_interface|.
// This function must be called within child processes.
static void SetParentProfileCollectorForChildProcess(
metrics::mojom::CallStackProfileCollectorPtr browser_interface);
protected:
// Test seam.
virtual void PassProfilesToMetricsProvider(SampledProfile sampled_profile);
private:
// The collected stack samples in proto buffer message format.
CallStackProfile proto_profile_;
// The current sample being recorded.
Sample sample_;
// The indexes of samples, indexed by the sample.
std::map<Sample, int> sample_index_;
// The indexes of modules, indexed by module's base_address.
std::map<uintptr_t, size_t> module_index_;
// The distinct modules in the current profile.
std::vector<base::ModuleCache::Module> modules_;
// The process milestones of a previous sample.
uint32_t milestones_ = 0;
// Callback made when sampling a profile completes.
base::OnceClosure completed_callback_;
// The parameters associated with the sampled profile.
const CallStackProfileParams profile_params_;
// The start time of a profile collection.
const base::TimeTicks profile_start_time_;
DISALLOW_COPY_AND_ASSIGN(LegacyCallStackProfileBuilder);
};
} // namespace metrics
#endif // COMPONENTS_METRICS_LEGACY_CALL_STACK_PROFILE_BUILDER_H_
......@@ -22,7 +22,7 @@
#include "base/threading/platform_thread.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/metrics/call_stack_profile_builder.h"
#include "components/metrics/legacy_call_stack_profile_builder.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/startup_metric_utils/browser/pref_names.h"
......@@ -579,8 +579,8 @@ void RecordBrowserMainMessageLoopStart(base::TimeTicks ticks,
RecordHardFaultHistogram();
// Record timing of the browser message-loop start time.
metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileBuilder::MAIN_LOOP_START);
metrics::LegacyCallStackProfileBuilder::SetProcessMilestone(
metrics::LegacyCallStackProfileBuilder::MAIN_LOOP_START);
if (!is_first_run && !g_process_creation_ticks.is_null()) {
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserMessageLoopStartTime",
......@@ -702,8 +702,8 @@ void RecordFirstWebContentsNonEmptyPaint(
if (!ShouldLogStartupHistogram())
return;
metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileBuilder::FIRST_NONEMPTY_PAINT);
metrics::LegacyCallStackProfileBuilder::SetProcessMilestone(
metrics::LegacyCallStackProfileBuilder::FIRST_NONEMPTY_PAINT);
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.NonEmptyPaint2",
g_process_creation_ticks, now);
......@@ -727,8 +727,8 @@ void RecordFirstWebContentsMainNavigationStart(base::TimeTicks ticks,
if (!ShouldLogStartupHistogram())
return;
metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileBuilder::MAIN_NAVIGATION_START);
metrics::LegacyCallStackProfileBuilder::SetProcessMilestone(
metrics::LegacyCallStackProfileBuilder::MAIN_NAVIGATION_START);
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100,
"Startup.FirstWebContents.MainNavigationStart", g_process_creation_ticks,
......@@ -758,8 +758,8 @@ void RecordFirstWebContentsMainNavigationFinished(base::TimeTicks ticks) {
if (!ShouldLogStartupHistogram())
return;
metrics::CallStackProfileBuilder::SetProcessMilestone(
metrics::CallStackProfileBuilder::MAIN_NAVIGATION_FINISHED);
metrics::LegacyCallStackProfileBuilder::SetProcessMilestone(
metrics::LegacyCallStackProfileBuilder::MAIN_NAVIGATION_FINISHED);
UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100,
"Startup.FirstWebContents.MainNavigationFinished",
......
......@@ -22,8 +22,6 @@ namespace {
class TracingProfileBuilder
: public base::StackSamplingProfiler::ProfileBuilder {
public:
void RecordAnnotations() override {}
void OnSampleCompleted(
std::vector<base::StackSamplingProfiler::Frame> frames) override {
if (frames.empty())
......
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