Commit fd8826a6 authored by Eric Seckler's avatar Eric Seckler Committed by Commit Bot

Reland "tracing: Enable startup tracing for spawned child processes"

This is a reland of e40282f6.

Includes a fix to BackgroundTracingActiveScenario, which could end up enabling
TraceLog without installing the TraceEventDataSource overrides on Android, see
patch set 1 -> 2. This likely caused the crashes observed in crbug.com/997582.

Original change's description:
> tracing: Enable startup tracing for spawned child processes
>
> Enables startup tracing for child processes spawned by the browser while
> a tracing session is active.
>
> This allows us to collect early trace events in the period of time
> before the child connects to the tracing service.
>
> Bug: 968424
> Change-Id: I1708cabae77cdd2ab3a33929c28cfab04eb723e3
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1755746
> Commit-Queue: Eric Seckler <eseckler@chromium.org>
> Reviewed-by: Avi Drissman <avi@chromium.org>
> Reviewed-by: ssid <ssid@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#689599}

Bug: 968424
Change-Id: Id69f0821671caf05238896d4a0e1b581b5d5be44
TBR: avi@chromium.org
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1782812
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarssid <ssid@chromium.org>
Cr-Commit-Position: refs/heads/master@{#694981}
parent 39ffb402
...@@ -255,6 +255,11 @@ class BASE_EXPORT TraceConfig { ...@@ -255,6 +255,11 @@ class BASE_EXPORT TraceConfig {
// Write the string representation of the CategoryFilter part. // Write the string representation of the CategoryFilter part.
std::string ToCategoryFilterString() const; std::string ToCategoryFilterString() const;
// Write the string representation of the trace options part (record mode,
// systrace, argument filtering). Does not include category filters, event
// filters, or memory dump configs.
std::string ToTraceOptionsString() const;
// Returns true if at least one category in the list is enabled by this // Returns true if at least one category in the list is enabled by this
// trace config. This is used to determine if the category filters are // trace config. This is used to determine if the category filters are
// enabled in the TRACE_* macros. // enabled in the TRACE_* macros.
...@@ -317,8 +322,6 @@ class BASE_EXPORT TraceConfig { ...@@ -317,8 +322,6 @@ class BASE_EXPORT TraceConfig {
void SetEventFiltersFromConfigList(const Value& event_filters); void SetEventFiltersFromConfigList(const Value& event_filters);
Value ToValue() const; Value ToValue() const;
std::string ToTraceOptionsString() const;
TraceRecordMode record_mode_; TraceRecordMode record_mode_;
size_t trace_buffer_size_in_events_ = 0; // 0 specifies default size size_t trace_buffer_size_in_events_ = 0; // 0 specifies default size
size_t trace_buffer_size_in_kb_ = 0; // 0 specifies default size size_t trace_buffer_size_in_kb_ = 0; // 0 specifies default size
......
...@@ -37,7 +37,7 @@ const char kTraceStartupDuration[] = "trace-startup-duration"; ...@@ -37,7 +37,7 @@ const char kTraceStartupDuration[] = "trace-startup-duration";
// all events since startup. // all events since startup.
const char kTraceStartupFile[] = "trace-startup-file"; const char kTraceStartupFile[] = "trace-startup-file";
// If supplied, sets the tracing record mode; otherwise, the default // If supplied, sets the tracing record mode and options; otherwise, the default
// "record-until-full" mode will be used. // "record-until-full" mode will be used.
const char kTraceStartupRecordMode[] = "trace-startup-record-mode"; const char kTraceStartupRecordMode[] = "trace-startup-record-mode";
...@@ -58,6 +58,11 @@ const char kTraceStartupRecordMode[] = "trace-startup-record-mode"; ...@@ -58,6 +58,11 @@ const char kTraceStartupRecordMode[] = "trace-startup-record-mode";
// through the normal methods for stopping system traces. // through the normal methods for stopping system traces.
const char kTraceStartupOwner[] = "trace-startup-owner"; const char kTraceStartupOwner[] = "trace-startup-owner";
// If the perfetto tracing backend is used, this enables privacy filtering in
// the TraceEvent data sources for the startup tracing session.
const char kTraceStartupEnablePrivacyFiltering[] =
"trace-startup-enable-privacy-filtering";
// Disables the perfetto tracing backend. We need a separate command line // Disables the perfetto tracing backend. We need a separate command line
// argument from the kTracingPerfettoBackend feature, because feature flags are // argument from the kTracingPerfettoBackend feature, because feature flags are
// parsed too late during startup for early startup tracing support. // parsed too late during startup for early startup tracing support.
......
...@@ -16,6 +16,7 @@ TRACING_EXPORT extern const char kTraceStartupDuration[]; ...@@ -16,6 +16,7 @@ TRACING_EXPORT extern const char kTraceStartupDuration[];
TRACING_EXPORT extern const char kTraceStartupFile[]; TRACING_EXPORT extern const char kTraceStartupFile[];
TRACING_EXPORT extern const char kTraceStartupRecordMode[]; TRACING_EXPORT extern const char kTraceStartupRecordMode[];
TRACING_EXPORT extern const char kTraceStartupOwner[]; TRACING_EXPORT extern const char kTraceStartupOwner[];
TRACING_EXPORT extern const char kTraceStartupEnablePrivacyFiltering[];
TRACING_EXPORT extern const char kDisablePerfetto[]; TRACING_EXPORT extern const char kDisablePerfetto[];
TRACING_EXPORT extern const char kEnablePerfetto[]; TRACING_EXPORT extern const char kEnablePerfetto[];
TRACING_EXPORT extern const char kPerfettoDisableInterning[]; TRACING_EXPORT extern const char kPerfettoDisableInterning[];
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "net/websockets/websocket_channel.h" #include "net/websockets/websocket_channel.h"
#include "services/service_manager/embedder/switches.h" #include "services/service_manager/embedder/switches.h"
#include "services/service_manager/public/cpp/constants.h" #include "services/service_manager/public/cpp/constants.h"
#include "services/tracing/public/cpp/trace_startup.h"
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
#include "content/browser/child_process_task_port_provider_mac.h" #include "content/browser/child_process_task_port_provider_mac.h"
...@@ -217,24 +218,7 @@ void BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags( ...@@ -217,24 +218,7 @@ void BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(
// static // static
void BrowserChildProcessHostImpl::CopyTraceStartupFlags( void BrowserChildProcessHostImpl::CopyTraceStartupFlags(
base::CommandLine* cmd_line) { base::CommandLine* cmd_line) {
if (tracing::TraceStartupConfig::GetInstance()->IsEnabled()) { tracing::PropagateTracingFlagsToChildProcessCmdLine(cmd_line);
const auto trace_config =
tracing::TraceStartupConfig::GetInstance()->GetTraceConfig();
if (!trace_config.IsArgumentFilterEnabled()) {
// The only trace option that we can pass through switches is the record
// mode. Other trace options should have the default value.
//
// TODO(chiniforooshan): Add other trace options to switches if, for
// example, they are used in a telemetry test that needs startup trace
// events from renderer processes.
cmd_line->AppendSwitchASCII(switches::kTraceStartup,
trace_config.ToCategoryFilterString());
cmd_line->AppendSwitchASCII(
switches::kTraceStartupRecordMode,
base::trace_event::TraceConfig::TraceRecordModeToStr(
trace_config.GetTraceRecordMode()));
}
}
} }
void BrowserChildProcessHostImpl::Launch( void BrowserChildProcessHostImpl::Launch(
......
...@@ -356,7 +356,25 @@ bool BackgroundTracingActiveScenario::StartTracing() { ...@@ -356,7 +356,25 @@ bool BackgroundTracingActiveScenario::StartTracing() {
uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE; uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
if (!chrome_config.event_filters().empty()) if (!chrome_config.event_filters().empty())
modes |= base::trace_event::TraceLog::FILTERING_MODE; modes |= base::trace_event::TraceLog::FILTERING_MODE;
// Perfetto backend configures buffer sizes when tracing is started in the
// service (see perfetto_config.cc). Zero them out here to avoid DCHECKs in
// TraceConfig::Merge.
if (tracing::TracingUsesPerfettoBackend()) {
chrome_config.SetTraceBufferSizeInKb(0);
chrome_config.SetTraceBufferSizeInEvents(0);
}
#if defined(OS_ANDROID)
// TODO(crbug.com/941318): Re-enable startup tracing for Perfetto backend on
// Android once all Perfetto-related deadlocks are resolved.
if (!tracing::TracingUsesPerfettoBackend()) {
base::trace_event::TraceLog::GetInstance()->SetEnabled(chrome_config,
modes);
}
#else // defined(OS_ANDROID)
base::trace_event::TraceLog::GetInstance()->SetEnabled(chrome_config, modes); base::trace_event::TraceLog::GetInstance()->SetEnabled(chrome_config, modes);
#endif // defined(OS_ANDROID)
DCHECK(!tracing_session_); DCHECK(!tracing_session_);
if (base::FeatureList::IsEnabled(features::kBackgroundTracingProtoOutput)) { if (base::FeatureList::IsEnabled(features::kBackgroundTracingProtoOutput)) {
......
...@@ -128,6 +128,10 @@ IN_PROC_BROWSER_TEST_F(StartupTracingInProcessTest, TestFilledStartupBuffer) { ...@@ -128,6 +128,10 @@ IN_PROC_BROWSER_TEST_F(StartupTracingInProcessTest, TestFilledStartupBuffer) {
auto config = tracing::TraceStartupConfig::GetInstance() auto config = tracing::TraceStartupConfig::GetInstance()
->GetDefaultBrowserStartupConfig(); ->GetDefaultBrowserStartupConfig();
if (tracing::TracingUsesPerfettoBackend()) {
config.SetTraceBufferSizeInEvents(0);
config.SetTraceBufferSizeInKb(0);
}
uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE; uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
base::trace_event::TraceLog::GetInstance()->SetEnabled(config, modes); base::trace_event::TraceLog::GetInstance()->SetEnabled(config, modes);
......
...@@ -71,14 +71,19 @@ perfetto::TraceConfig GetDefaultPerfettoConfig( ...@@ -71,14 +71,19 @@ perfetto::TraceConfig GetDefaultPerfettoConfig(
// 5 seconds of the trace (if we wrap around perfetto's central buffer). // 5 seconds of the trace (if we wrap around perfetto's central buffer).
perfetto_config.mutable_incremental_state_config()->set_clear_period_ms(5000); perfetto_config.mutable_incremental_state_config()->set_clear_period_ms(5000);
// We strip the process filter from the config string we send to Perfetto, // We strip the process filter from the config string we send to Perfetto, so
// so perfetto doesn't reject it from a future // perfetto doesn't reject it from a future TracingService::ChangeTraceConfig
// TracingService::ChangeTraceConfig call due to being an unsupported // call due to being an unsupported update. We also strip the trace buffer
// update. // size configuration to prevent chrome from rejecting an update to it after
base::trace_event::TraceConfig processfilter_stripped_config(chrome_config); // startup tracing via TraceConfig::Merge (see trace_startup.cc). For
processfilter_stripped_config.SetProcessFilterConfig( // perfetto, the buffer size is configured via perfetto's buffer config and
// only affects the perfetto service.
base::trace_event::TraceConfig stripped_config(chrome_config);
stripped_config.SetProcessFilterConfig(
base::trace_event::TraceConfig::ProcessFilterConfig()); base::trace_event::TraceConfig::ProcessFilterConfig());
std::string chrome_config_string = processfilter_stripped_config.ToString(); stripped_config.SetTraceBufferSizeInKb(0);
stripped_config.SetTraceBufferSizeInEvents(0);
std::string chrome_config_string = stripped_config.ToString();
// Capture actual trace events. // Capture actual trace events.
auto* trace_event_data_source = AddDataSourceConfig( auto* trace_event_data_source = AddDataSourceConfig(
......
...@@ -277,16 +277,24 @@ void TraceEventDataSource::RegisterWithTraceLog() { ...@@ -277,16 +277,24 @@ void TraceEventDataSource::RegisterWithTraceLog() {
&TraceEventDataSource::OnAddTraceEvent, &TraceEventDataSource::OnAddTraceEvent,
&TraceEventDataSource::FlushCurrentThread, &TraceEventDataSource::FlushCurrentThread,
&TraceEventDataSource::OnUpdateDuration); &TraceEventDataSource::OnUpdateDuration);
base::AutoLock l(lock_);
is_enabled_ = true;
} }
void TraceEventDataSource::UnregisterFromTraceLog() { void TraceEventDataSource::UnregisterFromTraceLog() {
RegisterTracedValueProtoWriter(false); RegisterTracedValueProtoWriter(false);
TraceLog::GetInstance()->SetAddTraceEventOverrides(nullptr, nullptr, nullptr); TraceLog::GetInstance()->SetAddTraceEventOverrides(nullptr, nullptr, nullptr);
base::AutoLock l(lock_); base::AutoLock l(lock_);
is_enabled_ = false;
flushing_trace_log_ = false; flushing_trace_log_ = false;
DCHECK(!flush_complete_task_); DCHECK(!flush_complete_task_);
} }
bool TraceEventDataSource::IsEnabled() {
base::AutoLock l(lock_);
return is_enabled_;
}
void TraceEventDataSource::SetupStartupTracing(bool privacy_filtering_enabled) { void TraceEventDataSource::SetupStartupTracing(bool privacy_filtering_enabled) {
{ {
base::AutoLock lock(lock_); base::AutoLock lock(lock_);
......
...@@ -140,6 +140,10 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource ...@@ -140,6 +140,10 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
startup_tracing_timeout_ = timeout_us; startup_tracing_timeout_ = timeout_us;
} }
bool privacy_filtering_enabled() const { return privacy_filtering_enabled_; }
bool IsEnabled();
private: private:
friend class base::NoDestructor<TraceEventDataSource>; friend class base::NoDestructor<TraceEventDataSource>;
...@@ -199,6 +203,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource ...@@ -199,6 +203,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
std::unique_ptr<perfetto::StartupTraceWriterRegistry> std::unique_ptr<perfetto::StartupTraceWriterRegistry>
startup_writer_registry_; startup_writer_registry_;
base::OneShotTimer startup_tracing_timer_; base::OneShotTimer startup_tracing_timer_;
bool is_enabled_ = false;
bool flushing_trace_log_ = false; bool flushing_trace_log_ = false;
base::OnceClosure flush_complete_task_; base::OnceClosure flush_complete_task_;
std::vector<std::string> histograms_; std::vector<std::string> histograms_;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "components/tracing/common/tracing_switches.h" #include "components/tracing/common/tracing_switches.h"
#include "services/tracing/public/cpp/perfetto/trace_event_data_source.h" #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h" #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
#include "services/tracing/public/cpp/trace_event_args_whitelist.h"
#include "services/tracing/public/cpp/tracing_features.h" #include "services/tracing/public/cpp/tracing_features.h"
namespace tracing { namespace tracing {
...@@ -43,21 +44,42 @@ void EnableStartupTracingIfNeeded() { ...@@ -43,21 +44,42 @@ void EnableStartupTracingIfNeeded() {
auto* startup_config = TraceStartupConfig::GetInstance(); auto* startup_config = TraceStartupConfig::GetInstance();
if (startup_config->IsEnabled()) { if (startup_config->IsEnabled()) {
const TraceConfig& trace_config = startup_config->GetTraceConfig(); TraceConfig trace_config = startup_config->GetTraceConfig();
// Make sure we only record whitelisted arguments even during early startup
// tracing if the config specifies argument filtering.
if (trace_config.IsArgumentFilterEnabled() &&
base::trace_event::TraceLog::GetInstance()
->GetArgumentFilterPredicate()
.is_null()) {
base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate(
base::BindRepeating(&IsTraceEventArgsWhitelisted));
base::trace_event::TraceLog::GetInstance()->SetMetadataFilterPredicate(
base::BindRepeating(&IsMetadataWhitelisted));
}
if (TracingUsesPerfettoBackend()) { if (TracingUsesPerfettoBackend()) {
// Perfetto backend configures buffer sizes when tracing is started in the
// service (see perfetto_config.cc). Zero them out here to avoid DCHECKs
// in TraceConfig::Merge.
trace_config.SetTraceBufferSizeInKb(0);
trace_config.SetTraceBufferSizeInEvents(0);
if (trace_config.IsCategoryGroupEnabled( if (trace_config.IsCategoryGroupEnabled(
TRACE_DISABLED_BY_DEFAULT("cpu_profiler"))) { TRACE_DISABLED_BY_DEFAULT("cpu_profiler"))) {
TracingSamplerProfiler::SetupStartupTracing(); TracingSamplerProfiler::SetupStartupTracing();
} }
TraceEventDataSource::GetInstance()->SetupStartupTracing( TraceEventDataSource::GetInstance()->SetupStartupTracing(
startup_config->GetSessionOwner() == startup_config->GetSessionOwner() ==
TraceStartupConfig::SessionOwner::kBackgroundTracing); TraceStartupConfig::SessionOwner::kBackgroundTracing ||
command_line.HasSwitch(
switches::kTraceStartupEnablePrivacyFiltering));
} }
uint8_t modes = TraceLog::RECORDING_MODE; uint8_t modes = TraceLog::RECORDING_MODE;
if (!trace_config.event_filters().empty()) if (!trace_config.event_filters().empty())
modes |= TraceLog::FILTERING_MODE; modes |= TraceLog::FILTERING_MODE;
trace_log->SetEnabled(startup_config->GetTraceConfig(), modes); trace_log->SetEnabled(trace_config, modes);
} else if (command_line.HasSwitch(switches::kTraceToConsole)) { } else if (command_line.HasSwitch(switches::kTraceToConsole)) {
// TODO(eseckler): Remove ability to trace to the console, perfetto doesn't // TODO(eseckler): Remove ability to trace to the console, perfetto doesn't
// support this and noone seems to use it. // support this and noone seems to use it.
...@@ -91,4 +113,67 @@ void InitTracingPostThreadPoolStartAndFeatureList() { ...@@ -91,4 +113,67 @@ void InitTracingPostThreadPoolStartAndFeatureList() {
} }
} }
void PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine* cmd_line) {
base::trace_event::TraceLog* trace_log =
base::trace_event::TraceLog::GetInstance();
if (!trace_log->IsEnabled())
return;
// It's possible that tracing is enabled only for atrace, in which case the
// TraceEventDataSource isn't registered. In that case, there's no reason to
// enable startup tracing in the child process (and we wouldn't know the
// correct value for privacy_filtering_enabled below).
if (TracingUsesPerfettoBackend() &&
!TraceEventDataSource::GetInstance()->IsEnabled()) {
return;
}
// The child process startup may race with a concurrent disabling of the
// tracing session by the tracing service. To avoid being stuck in startup
// tracing mode forever, the child process will discard the startup session
// after a timeout (|startup_tracing_timer_| in TraceEventDataSource).
//
// Note that we disregard the config's process filter, since it's possible
// that the trace consumer will update the config to include the process
// shortly. Otherwise, the startup tracing timeout in the child will
// eventually disable tracing for the process.
const auto trace_config = trace_log->GetCurrentTraceConfig();
// We can't currently propagate event filter options, memory dump configs, or
// trace buffer sizes via command line flags (they only support categories,
// trace options, record mode). If event filters are set, we bail out here to
// avoid recording events that we shouldn't in the child process. Even if
// memory dump config is set, it's OK to propagate the remaining config,
// because the child won't record events it shouldn't without it and will
// adopt the memory dump config once it connects to the tracing service.
// Buffer sizes only affect the legacy tracing backend's startup tracing, so
// we only bail out if perfetto is disabled.
//
// TODO(eseckler): Support propagating the full config via command line flags
// somehow (--trace-config?). This will also need some rethinking to support
// multiple concurrent tracing sessions in the future.
if (!trace_config.event_filters().empty() ||
((trace_config.GetTraceBufferSizeInEvents() ||
trace_config.GetTraceBufferSizeInKb()) &&
!TracingUsesPerfettoBackend())) {
return;
}
// Make sure that the startup session uses privacy filtering mode if it's
// enabled for the browser's session.
if (TracingUsesPerfettoBackend() &&
TraceEventDataSource::GetInstance()->privacy_filtering_enabled()) {
cmd_line->AppendSwitch(switches::kTraceStartupEnablePrivacyFiltering);
}
cmd_line->AppendSwitchASCII(switches::kTraceStartup,
trace_config.ToCategoryFilterString());
// The argument filtering setting is passed via trace options as part of
// --trace-startup-record-mode.
cmd_line->AppendSwitchASCII(switches::kTraceStartupRecordMode,
trace_config.ToTraceOptionsString());
}
} // namespace tracing } // namespace tracing
...@@ -7,6 +7,10 @@ ...@@ -7,6 +7,10 @@
#include "base/component_export.h" #include "base/component_export.h"
namespace base {
class CommandLine;
} // namespace base
namespace tracing { namespace tracing {
// Returns true if InitTracingPostThreadPoolStartAndFeatureList has been called // Returns true if InitTracingPostThreadPoolStartAndFeatureList has been called
...@@ -23,6 +27,11 @@ void COMPONENT_EXPORT(TRACING_CPP) EnableStartupTracingIfNeeded(); ...@@ -23,6 +27,11 @@ void COMPONENT_EXPORT(TRACING_CPP) EnableStartupTracingIfNeeded();
void COMPONENT_EXPORT(TRACING_CPP) void COMPONENT_EXPORT(TRACING_CPP)
InitTracingPostThreadPoolStartAndFeatureList(); InitTracingPostThreadPoolStartAndFeatureList();
// If tracing is enabled, grabs the current trace config & mode and tells the
// child to begin tracing right away via startup tracing command line flags.
void COMPONENT_EXPORT(TRACING_CPP)
PropagateTracingFlagsToChildProcessCmdLine(base::CommandLine* cmd_line);
} // namespace tracing } // namespace tracing
#endif // SERVICES_TRACING_PUBLIC_CPP_TRACE_STARTUP_H_ #endif // SERVICES_TRACING_PUBLIC_CPP_TRACE_STARTUP_H_
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