blob: b6826bf59ff9afa26b52f3e09b3fd7bf260bcd76 [file] [log] [blame]
// Copyright 2019 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 "services/tracing/public/cpp/perfetto/perfetto_config.h"
#include <cstdint>
#include <string>
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event.h"
#include "base/tracing/trace_time.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
namespace tracing {
namespace {
perfetto::TraceConfig::DataSource* AddDataSourceConfig(
perfetto::TraceConfig* perfetto_config,
const char* name,
const std::string& chrome_config_string,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
const std::string& json_agent_label_filter) {
auto* data_source = perfetto_config->add_data_sources();
auto* source_config = data_source->mutable_config();
#if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
if (!strcmp(name, tracing::mojom::kTraceEventDataSourceName)) {
source_config->set_name("track_event");
} else {
source_config->set_name(name);
}
#else
source_config->set_name(name);
#endif
source_config->set_target_buffer(0);
auto* chrome_config = source_config->mutable_chrome_config();
chrome_config->set_trace_config(chrome_config_string);
chrome_config->set_privacy_filtering_enabled(privacy_filtering_enabled);
chrome_config->set_convert_to_legacy_json(convert_to_legacy_json);
chrome_config->set_client_priority(client_priority);
if (!json_agent_label_filter.empty())
chrome_config->set_json_agent_label_filter(json_agent_label_filter);
#if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
if (!strcmp(name, tracing::mojom::kTraceEventDataSourceName)) {
base::trace_event::TraceConfig base_config(chrome_config_string);
perfetto::protos::gen::TrackEventConfig te_cfg;
// If no categories are explicitly enabled, enable the default ones.
// Otherwise only matching categories are enabled.
if (!base_config.category_filter().included_categories().empty())
te_cfg.add_disabled_categories("*");
for (const auto& excluded :
base_config.category_filter().excluded_categories()) {
te_cfg.add_disabled_categories(excluded);
}
for (const auto& included :
base_config.category_filter().included_categories()) {
te_cfg.add_enabled_categories(included);
}
for (const auto& disabled :
base_config.category_filter().disabled_categories()) {
te_cfg.add_enabled_categories(disabled);
}
source_config->set_track_event_config_raw(te_cfg.SerializeAsString());
}
#endif // BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
return data_source;
}
void AddDataSourceConfigs(
perfetto::TraceConfig* perfetto_config,
const base::trace_event::TraceConfig::ProcessFilterConfig& process_filters,
const base::trace_event::TraceConfig& stripped_config,
const std::set<std::string>& source_names,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
const std::string& json_agent_label_filter) {
const std::string chrome_config_string = stripped_config.ToString();
if (stripped_config.IsCategoryGroupEnabled(
base::trace_event::MemoryDumpManager::kTraceCategory)) {
DCHECK(source_names.empty() ||
source_names.count(
tracing::mojom::kMemoryInstrumentationDataSourceName));
AddDataSourceConfig(
perfetto_config, tracing::mojom::kMemoryInstrumentationDataSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
AddDataSourceConfig(
perfetto_config, tracing::mojom::kNativeHeapProfilerSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
}
// Capture actual trace events.
if (source_names.empty() ||
source_names.count(tracing::mojom::kTraceEventDataSourceName) == 1) {
auto* trace_event_data_source = AddDataSourceConfig(
perfetto_config, tracing::mojom::kTraceEventDataSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
for (auto& enabled_pid : process_filters.included_process_ids()) {
*trace_event_data_source->add_producer_name_filter() = base::StrCat(
{mojom::kPerfettoProducerNamePrefix,
base::NumberToString(static_cast<uint32_t>(enabled_pid))});
}
}
// Capture system trace events if supported and enabled. The datasources will
// only emit events if system tracing is enabled in |chrome_config|.
if (!privacy_filtering_enabled) {
// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
// complete.
#if BUILDFLAG(IS_CHROMEOS_ASH) || \
(BUILDFLAG(IS_CHROMECAST) && defined(OS_LINUX))
if (source_names.empty() ||
source_names.count(tracing::mojom::kSystemTraceDataSourceName) == 1) {
AddDataSourceConfig(
perfetto_config, tracing::mojom::kSystemTraceDataSourceName,
chrome_config_string, privacy_filtering_enabled,
convert_to_legacy_json, client_priority, json_agent_label_filter);
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (source_names.empty() ||
source_names.count(tracing::mojom::kArcTraceDataSourceName) == 1) {
AddDataSourceConfig(
perfetto_config, tracing::mojom::kArcTraceDataSourceName,
chrome_config_string, privacy_filtering_enabled,
convert_to_legacy_json, client_priority, json_agent_label_filter);
}
#endif
}
// Also capture global metadata.
if (source_names.empty() ||
source_names.count(tracing::mojom::kMetaDataSourceName) == 1) {
AddDataSourceConfig(perfetto_config, tracing::mojom::kMetaDataSourceName,
chrome_config_string, privacy_filtering_enabled,
convert_to_legacy_json, client_priority,
json_agent_label_filter);
}
if (stripped_config.IsCategoryGroupEnabled(
TRACE_DISABLED_BY_DEFAULT("cpu_profiler"))) {
DCHECK_EQ(
1u, source_names.empty() ||
source_names.count(tracing::mojom::kSamplerProfilerSourceName));
AddDataSourceConfig(
perfetto_config, tracing::mojom::kSamplerProfilerSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
}
if (stripped_config.IsCategoryGroupEnabled(
TRACE_DISABLED_BY_DEFAULT("java-heap-profiler"))) {
DCHECK_EQ(1u, source_names.empty() ||
source_names.count(
tracing::mojom::kJavaHeapProfilerSourceName));
AddDataSourceConfig(
perfetto_config, tracing::mojom::kJavaHeapProfilerSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
}
if (source_names.empty() ||
source_names.count(tracing::mojom::kReachedCodeProfilerSourceName) == 1) {
AddDataSourceConfig(
perfetto_config, tracing::mojom::kReachedCodeProfilerSourceName,
chrome_config_string, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
}
}
} // namespace
perfetto::TraceConfig GetDefaultPerfettoConfig(
const base::trace_event::TraceConfig& chrome_config,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
const std::string& json_agent_label_filter) {
return GetPerfettoConfigWithDataSources(
chrome_config, {}, privacy_filtering_enabled, convert_to_legacy_json,
client_priority, json_agent_label_filter);
}
perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP)
GetPerfettoConfigWithDataSources(
const base::trace_event::TraceConfig& chrome_config,
const std::set<std::string>& source_names,
bool privacy_filtering_enabled,
bool convert_to_legacy_json,
perfetto::protos::gen::ChromeConfig::ClientPriority client_priority,
const std::string& json_agent_label_filter) {
perfetto::TraceConfig perfetto_config;
size_t size_limit = chrome_config.GetTraceBufferSizeInKb();
if (size_limit == 0) {
// TODO(eseckler): Reduce the default buffer size after benchmarks set what
// they require. Should also invest some time to reduce the overhead of
// begin/end pairs further.
size_limit = 200 * 1024;
}
auto* buffer_config = perfetto_config.add_buffers();
buffer_config->set_size_kb(size_limit);
switch (chrome_config.GetTraceRecordMode()) {
case base::trace_event::RECORD_UNTIL_FULL:
case base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE:
buffer_config->set_fill_policy(
perfetto::TraceConfig::BufferConfig::DISCARD);
break;
case base::trace_event::RECORD_CONTINUOUSLY:
buffer_config->set_fill_policy(
perfetto::TraceConfig::BufferConfig::RING_BUFFER);
break;
case base::trace_event::ECHO_TO_CONSOLE:
NOTREACHED();
break;
}
auto* builtin_data_sources = perfetto_config.mutable_builtin_data_sources();
// Chrome uses CLOCK_MONOTONIC as its trace clock on Posix. To avoid that
// trace processor converts Chrome's event timestamps into CLOCK_BOOTTIME
// during import, we set the trace clock here (the service will emit it into
// the trace's ClockSnapshots). See also crbug.com/1060400, where the
// conversion to BOOTTIME caused CrOS and chromecast system data source data
// to be misaligned.
builtin_data_sources->set_primary_trace_clock(
static_cast<perfetto::protos::gen::BuiltinClock>(
base::tracing::kTraceClockId));
// Chrome emits system / trace config metadata itself.
builtin_data_sources->set_disable_trace_config(privacy_filtering_enabled);
builtin_data_sources->set_disable_system_info(privacy_filtering_enabled);
builtin_data_sources->set_disable_service_events(privacy_filtering_enabled);
// Clear incremental state every 5 seconds, so that we lose at most the first
// 5 seconds of the trace (if we wrap around perfetto's central buffer).
perfetto_config.mutable_incremental_state_config()->set_clear_period_ms(5000);
// We strip the process filter from the config string we send to Perfetto, so
// perfetto doesn't reject it from a future TracingService::ChangeTraceConfig
// call due to being an unsupported update. We also strip the trace buffer
// size configuration to prevent chrome from rejecting an update to it after
// startup tracing via TraceConfig::Merge (see trace_startup.cc). For
// 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());
stripped_config.SetTraceBufferSizeInKb(0);
stripped_config.SetTraceBufferSizeInEvents(0);
AddDataSourceConfigs(&perfetto_config, chrome_config.process_filter_config(),
stripped_config, source_names, privacy_filtering_enabled,
convert_to_legacy_json, client_priority,
json_agent_label_filter);
return perfetto_config;
}
} // namespace tracing