Commit 2f56155d authored by Eric Seckler's avatar Eric Seckler Committed by Commit Bot

Reland "perfetto: Split COMPLETE events into BEGIN/END pairs"

This is a reland of 4da16526.

Relanding after the bad event nesting in v8's GC events was fixed.
Also increases the default trace buffer size, because the traces
with split events are slightly larger and cause some benchmarks to
lose data otherwise. Furthermore, includes a fix for a bug that
caused us to emit COMPLETE events as atrace events twice.

Original change's description:
> perfetto: Split COMPLETE events into BEGIN/END pairs
>
> There are a few reasons why this is desirable:
> (1) Reduces need for complete event stack in ThreadLocalEventSinks,
>     which was brittle before (e.g. crbug.com/983307).
> (2) Makes it possible to flush event sinks while tracing in the future
>     without losing not-yet-completed COMPLETE events from the stack
>     (streamed tracing use case). Events that didn't end before the
>     flush will still be present in the trace as BEGIN only.
> (3) Prevents reordering of nested COMPLETE events - something which
>     could confuse TraceProcessor in the past (events with identical
>     begin timestamps would be imported incorrectly).
>
> To achieve this, this patch also plumbs the EXPLICIT_TIMESTAMP flag
> and thread id through to TraceLog::UpdateTraceEventDurationExplicit,
> because it seems that android can add COMPLETE events with explicit
> timestamps / threads [1].
>
> [1] https://cs.chromium.org/chromium/src/base/android/early_trace_event_binding.cc?q=INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMPS&ss=chromium&l=31
>
> Bug: 983307, 928738, 1006770
> Change-Id: I66e685c04c068646d550f182185d3c45febcbfa8
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899852
> Commit-Queue: Eric Seckler <eseckler@chromium.org>
> Reviewed-by: oysteine <oysteine@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#716871}

Bug: 983307, 928738, 1006770
Change-Id: I478ab4ade4bf5182d41cedb2f0b5fd22ba2e1604
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1931750
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Reviewed-by: default avataroysteine <oysteine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718975}
parent 440758bc
...@@ -174,8 +174,11 @@ ...@@ -174,8 +174,11 @@
// const unsigned char* category_group_enabled, // const unsigned char* category_group_enabled,
// const char* name, // const char* name,
// base::trace_event::TraceEventHandle id, // base::trace_event::TraceEventHandle id,
// const TimeTicks& now, // int thread_id,
// const ThreadTicks* thread_now) // bool explicit_timestamps,
// const base::TimeTicks& now,
// const base::ThreadTicks& thread_now,
// base::trace_event::ThreadInstructionCount thread_instruction_now)
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION_EXPLICIT \ #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION_EXPLICIT \
trace_event_internal::UpdateTraceEventDurationExplicit trace_event_internal::UpdateTraceEventDurationExplicit
...@@ -379,28 +382,29 @@ ...@@ -379,28 +382,29 @@
// Implementation detail: internal macro to create static category and add // Implementation detail: internal macro to create static category and add
// event if the category is enabled. // event if the category is enabled.
#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMPS( \ #define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMPS( \
category_group, name, id, thread_id, begin_timestamp, end_timestamp, \ category_group, name, id, thread_id, begin_timestamp, end_timestamp, \
thread_end_timestamp, flags, ...) \ thread_end_timestamp, flags, ...) \
do { \ do { \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
trace_event_internal::TraceID trace_event_trace_id((id)); \ trace_event_internal::TraceID trace_event_trace_id((id)); \
unsigned int trace_event_flags = \ unsigned int trace_event_flags = \
flags | trace_event_trace_id.id_flags(); \ flags | trace_event_trace_id.id_flags(); \
const unsigned char* uid_category_group_enabled = \ const unsigned char* uid_category_group_enabled = \
INTERNAL_TRACE_EVENT_UID(category_group_enabled); \ INTERNAL_TRACE_EVENT_UID(category_group_enabled); \
auto handle = \ auto handle = \
trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \ trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
TRACE_EVENT_PHASE_COMPLETE, uid_category_group_enabled, name, \ TRACE_EVENT_PHASE_COMPLETE, uid_category_group_enabled, name, \
trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \ trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \
thread_id, begin_timestamp, \ thread_id, begin_timestamp, \
trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \ trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
trace_event_internal::kNoId, ##__VA_ARGS__); \ trace_event_internal::kNoId, ##__VA_ARGS__); \
TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION_EXPLICIT( \ TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION_EXPLICIT( \
uid_category_group_enabled, name, handle, end_timestamp, \ uid_category_group_enabled, name, handle, thread_id, \
thread_end_timestamp, base::trace_event::ThreadInstructionCount()); \ /*explicit_timestamps=*/true, end_timestamp, thread_end_timestamp, \
} \ base::trace_event::ThreadInstructionCount()); \
} \
} while (0) } while (0)
// The linked ID will not be mangled. // The linked ID will not be mangled.
...@@ -717,6 +721,8 @@ void BASE_EXPORT UpdateTraceEventDurationExplicit( ...@@ -717,6 +721,8 @@ void BASE_EXPORT UpdateTraceEventDurationExplicit(
const unsigned char* category_group_enabled, const unsigned char* category_group_enabled,
const char* name, const char* name,
base::trace_event::TraceEventHandle handle, base::trace_event::TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const base::TimeTicks& now, const base::TimeTicks& now,
const base::ThreadTicks& thread_now, const base::ThreadTicks& thread_now,
base::trace_event::ThreadInstructionCount thread_instruction_now); base::trace_event::ThreadInstructionCount thread_instruction_now);
......
...@@ -1415,15 +1415,19 @@ void TraceLog::UpdateTraceEventDuration( ...@@ -1415,15 +1415,19 @@ void TraceLog::UpdateTraceEventDuration(
if (!category_group_enabled_local) if (!category_group_enabled_local)
return; return;
UpdateTraceEventDurationExplicit(category_group_enabled, name, handle, UpdateTraceEventDurationExplicit(
OffsetNow(), ThreadNow(), category_group_enabled, name, handle,
ThreadInstructionNow()); static_cast<int>(base::PlatformThread::CurrentId()),
/*explicit_timestamps=*/false, OffsetNow(), ThreadNow(),
ThreadInstructionNow());
} }
void TraceLog::UpdateTraceEventDurationExplicit( void TraceLog::UpdateTraceEventDurationExplicit(
const unsigned char* category_group_enabled, const unsigned char* category_group_enabled,
const char* name, const char* name,
TraceEventHandle handle, TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const TimeTicks& now, const TimeTicks& now,
const ThreadTicks& thread_now, const ThreadTicks& thread_now,
ThreadInstructionCount thread_instruction_now) { ThreadInstructionCount thread_instruction_now) {
...@@ -1448,7 +1452,9 @@ void TraceLog::UpdateTraceEventDurationExplicit( ...@@ -1448,7 +1452,9 @@ void TraceLog::UpdateTraceEventDurationExplicit(
auto update_duration_override = auto update_duration_override =
update_duration_override_.load(std::memory_order_relaxed); update_duration_override_.load(std::memory_order_relaxed);
if (update_duration_override) { if (update_duration_override) {
update_duration_override(handle, now, thread_now, thread_instruction_now); update_duration_override(category_group_enabled, name, handle, thread_id,
explicit_timestamps, now, thread_now,
thread_instruction_now);
return; return;
} }
} }
...@@ -1826,13 +1832,15 @@ void UpdateTraceEventDurationExplicit( ...@@ -1826,13 +1832,15 @@ void UpdateTraceEventDurationExplicit(
const unsigned char* category_group_enabled, const unsigned char* category_group_enabled,
const char* name, const char* name,
base::trace_event::TraceEventHandle handle, base::trace_event::TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const base::TimeTicks& now, const base::TimeTicks& now,
const base::ThreadTicks& thread_now, const base::ThreadTicks& thread_now,
base::trace_event::ThreadInstructionCount thread_instruction_now) { base::trace_event::ThreadInstructionCount thread_instruction_now) {
return base::trace_event::TraceLog::GetInstance() return base::trace_event::TraceLog::GetInstance()
->UpdateTraceEventDurationExplicit(category_group_enabled, name, handle, ->UpdateTraceEventDurationExplicit(category_group_enabled, name, handle,
now, thread_now, thread_id, explicit_timestamps, now,
thread_instruction_now); thread_now, thread_instruction_now);
} }
ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient( ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
......
...@@ -201,7 +201,11 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider { ...@@ -201,7 +201,11 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
TraceEventHandle* handle); TraceEventHandle* handle);
using OnFlushFunction = void (*)(); using OnFlushFunction = void (*)();
using UpdateDurationFunction = using UpdateDurationFunction =
void (*)(TraceEventHandle handle, void (*)(const unsigned char* category_group_enabled,
const char* name,
TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const TimeTicks& now, const TimeTicks& now,
const ThreadTicks& thread_now, const ThreadTicks& thread_now,
ThreadInstructionCount thread_instruction_now); ThreadInstructionCount thread_instruction_now);
...@@ -298,6 +302,8 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider { ...@@ -298,6 +302,8 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
const unsigned char* category_group_enabled, const unsigned char* category_group_enabled,
const char* name, const char* name,
TraceEventHandle handle, TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const TimeTicks& now, const TimeTicks& now,
const ThreadTicks& thread_now, const ThreadTicks& thread_now,
ThreadInstructionCount thread_instruction_now); ThreadInstructionCount thread_instruction_now);
......
...@@ -42,7 +42,7 @@ perfetto::TraceConfig GetDefaultPerfettoConfig( ...@@ -42,7 +42,7 @@ perfetto::TraceConfig GetDefaultPerfettoConfig(
size_t size_limit = chrome_config.GetTraceBufferSizeInKb(); size_t size_limit = chrome_config.GetTraceBufferSizeInKb();
if (size_limit == 0) { if (size_limit == 0) {
size_limit = 100 * 1024; size_limit = 150 * 1024;
} }
auto* buffer_config = perfetto_config.add_buffers(); auto* buffer_config = perfetto_config.add_buffers();
buffer_config->set_size_kb(size_limit); buffer_config->set_size_kb(size_limit);
......
...@@ -895,7 +895,11 @@ void TraceEventDataSource::OnAddTraceEvent( ...@@ -895,7 +895,11 @@ void TraceEventDataSource::OnAddTraceEvent(
// static // static
void TraceEventDataSource::OnUpdateDuration( void TraceEventDataSource::OnUpdateDuration(
const unsigned char* category_group_enabled,
const char* name,
base::trace_event::TraceEventHandle handle, base::trace_event::TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const base::TimeTicks& now, const base::TimeTicks& now,
const base::ThreadTicks& thread_now, const base::ThreadTicks& thread_now,
base::trace_event::ThreadInstructionCount thread_instruction_now) { base::trace_event::ThreadInstructionCount thread_instruction_now) {
...@@ -908,8 +912,9 @@ void TraceEventDataSource::OnUpdateDuration( ...@@ -908,8 +912,9 @@ void TraceEventDataSource::OnUpdateDuration(
auto* thread_local_event_sink = static_cast<TrackEventThreadLocalEventSink*>( auto* thread_local_event_sink = static_cast<TrackEventThreadLocalEventSink*>(
ThreadLocalEventSinkSlot()->Get()); ThreadLocalEventSinkSlot()->Get());
if (thread_local_event_sink) { if (thread_local_event_sink) {
thread_local_event_sink->UpdateDuration(handle, now, thread_now, thread_local_event_sink->UpdateDuration(
thread_instruction_now); category_group_enabled, name, handle, thread_id, explicit_timestamps,
now, thread_now, thread_instruction_now);
} }
} }
......
...@@ -230,7 +230,11 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource ...@@ -230,7 +230,11 @@ class COMPONENT_EXPORT(TRACING_CPP) TraceEventDataSource
bool thread_will_flush, bool thread_will_flush,
base::trace_event::TraceEventHandle* handle); base::trace_event::TraceEventHandle* handle);
static void OnUpdateDuration( static void OnUpdateDuration(
const unsigned char* category_group_enabled,
const char* name,
base::trace_event::TraceEventHandle handle, base::trace_event::TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const base::TimeTicks& now, const base::TimeTicks& now,
const base::ThreadTicks& thread_now, const base::ThreadTicks& thread_now,
base::trace_event::ThreadInstructionCount thread_instruction_now); base::trace_event::ThreadInstructionCount thread_instruction_now);
......
...@@ -337,8 +337,13 @@ class TraceEventDataSourceTest : public testing::Test { ...@@ -337,8 +337,13 @@ class TraceEventDataSourceTest : public testing::Test {
last_thread_time_ += packet->track_event().thread_time_delta_us(); last_thread_time_ += packet->track_event().thread_time_delta_us();
} }
EXPECT_EQ(packet->track_event().category_iids_size(), 1); if (category_iid > 0) {
EXPECT_EQ(packet->track_event().category_iids(0), category_iid); EXPECT_EQ(packet->track_event().category_iids_size(), 1);
EXPECT_EQ(packet->track_event().category_iids(0), category_iid);
} else {
EXPECT_EQ(packet->track_event().category_iids_size(), 0);
}
EXPECT_TRUE(packet->track_event().has_legacy_event()); EXPECT_TRUE(packet->track_event().has_legacy_event());
const auto& legacy_event = packet->track_event().legacy_event(); const auto& legacy_event = packet->track_event().legacy_event();
...@@ -932,44 +937,56 @@ TEST_F(TraceEventDataSourceTest, UpdateDurationOfCompleteEvent) { ...@@ -932,44 +937,56 @@ TEST_F(TraceEventDataSourceTest, UpdateDurationOfCompleteEvent) {
trace_event_internal::TraceID trace_event_trace_id = trace_event_internal::TraceID trace_event_trace_id =
trace_event_internal::kNoId; trace_event_internal::kNoId;
// COMPLETE events are split into a BEGIN/END event pair. Adding the event
// writes the BEGIN event immediately.
auto handle = trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( auto handle = trace_event_internal::AddTraceEventWithThreadIdAndTimestamp(
TRACE_EVENT_PHASE_COMPLETE, category_group_enabled, kEventName, TRACE_EVENT_PHASE_COMPLETE, category_group_enabled, kEventName,
trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), trace_event_trace_id.scope(), trace_event_trace_id.raw_id(),
1 /* thread_id */, /*thread_id=*/1,
base::TimeTicks() + base::TimeDelta::FromMicroseconds(10), base::TimeTicks() + base::TimeDelta::FromMicroseconds(10),
trace_event_trace_id.id_flags() | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, trace_event_trace_id.id_flags() | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP,
trace_event_internal::kNoId); trace_event_internal::kNoId);
EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 2u);
auto* b_packet = producer_client()->GetFinalizedPacket(1);
ExpectTraceEvent(
b_packet, /*category_iid=*/1u, /*name_iid=*/1u, TRACE_EVENT_PHASE_BEGIN,
TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP | TRACE_EVENT_FLAG_HAS_ID, /*id=*/0u,
/*absolute_timestamp=*/10, /*tid_override=*/1, /*pid_override=*/0);
// Updating the duration of the event as it goes out of scope results in the
// corresponding END event being written. These END events don't contain any
// event names or categories in the proto format.
base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDurationExplicit( base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDurationExplicit(
category_group_enabled, kEventName, handle, category_group_enabled, kEventName, handle, /*thread_id=*/1,
/*explicit_timestamps=*/true,
base::TimeTicks() + base::TimeDelta::FromMicroseconds(30), base::TimeTicks() + base::TimeDelta::FromMicroseconds(30),
base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50), base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50),
base::trace_event::ThreadInstructionCount()); base::trace_event::ThreadInstructionCount());
// The call to UpdateTraceEventDurationExplicit should have successfully EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 3u);
// updated the duration of the event which was added in the auto* e_packet = producer_client()->GetFinalizedPacket(2);
// AddTraceEventWithThreadIdAndTimestamp call.
EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 2u);
auto* e_packet = producer_client()->GetFinalizedPacket(1);
ExpectTraceEvent( ExpectTraceEvent(
e_packet, /*category_iid=*/1u, /*name_iid=*/1u, e_packet, /*category_iid=*/0u, /*name_iid=*/0u, TRACE_EVENT_PHASE_END,
TRACE_EVENT_PHASE_COMPLETE, TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, /*id=*/0u,
TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP | TRACE_EVENT_FLAG_HAS_ID, /*id=*/0u, /*absolute_timestamp=*/30, /*tid_override=*/1, /*pid_override=*/0);
/*absolute_timestamp=*/10, /*tid_override=*/1, /*pid_override=*/0,
/*duration=*/20);
// Updating the duration of an invalid event should cause no further events to // Updating the duration of an event that wasn't added before tracing begun
// be emitted. // will only emit an END event, again without category or name.
handle.event_index = 0; handle.event_index = 0;
base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDurationExplicit( base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDurationExplicit(
category_group_enabled, kEventName, handle, category_group_enabled, "other_event_name", handle, /*thread_id=*/1,
base::TimeTicks() + base::TimeDelta::FromMicroseconds(30), /*explicit_timestamps=*/true,
base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50), base::TimeTicks() + base::TimeDelta::FromMicroseconds(40),
base::ThreadTicks() + base::TimeDelta::FromMicroseconds(60),
base::trace_event::ThreadInstructionCount()); base::trace_event::ThreadInstructionCount());
// No further packets should have been emitted. EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 4u);
EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 2u); auto* e2_packet = producer_client()->GetFinalizedPacket(3);
ExpectTraceEvent(
e2_packet, /*category_iid=*/0u, /*name_iid=*/0u, TRACE_EVENT_PHASE_END,
TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, /*id=*/0u,
/*absolute_timestamp=*/40, /*tid_override=*/1, /*pid_override=*/0);
} }
// TODO(eseckler): Add a test with multiple events + same strings (cat, name, // TODO(eseckler): Add a test with multiple events + same strings (cat, name,
......
...@@ -36,12 +36,6 @@ namespace tracing { ...@@ -36,12 +36,6 @@ namespace tracing {
namespace { namespace {
// To mark TraceEvent handles that have been added by Perfetto,
// we use the chunk index so high that TraceLog would've asserted
// at this point anyway.
constexpr uint32_t kMagicChunkIndex =
base::trace_event::TraceBufferChunk::kMaxChunkIndex;
// Replacement string for names of events with TRACE_EVENT_FLAG_COPY. // Replacement string for names of events with TRACE_EVENT_FLAG_COPY.
const char* const kPrivacyFiltered = "PRIVACY_FILTERED"; const char* const kPrivacyFiltered = "PRIVACY_FILTERED";
...@@ -195,38 +189,11 @@ void TrackEventThreadLocalEventSink::ClearIncrementalState() { ...@@ -195,38 +189,11 @@ void TrackEventThreadLocalEventSink::ClearIncrementalState() {
incremental_state_reset_id_.fetch_add(1u, std::memory_order_relaxed); incremental_state_reset_id_.fetch_add(1u, std::memory_order_relaxed);
} }
bool TrackEventThreadLocalEventSink::MaybeHandleCompleteEvent(
base::trace_event::TraceEvent* trace_event,
base::trace_event::TraceEventHandle* handle) {
// TODO(eseckler): Support splitting COMPLETE events into BEGIN/END pairs.
// For now, we emit them as legacy events so that the generated JSON trace
// size remains small.
if (handle && trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE) {
// 'X' phase events are added through a scoped object and
// will have its duration updated when said object drops off
// the stack; keep a copy of the event around instead of
// writing it into SHM, until we have the duration.
// We can't keep the TraceEvent around in the scoped object
// itself as that causes a lot more codegen in the callsites
// and bloats the binary size too much (due to the increased
// sizeof() of the scoped object itself).
DCHECK_LT(current_stack_depth_, kMaxCompleteEventDepth);
if (current_stack_depth_ >= kMaxCompleteEventDepth) {
return true;
}
complete_event_stack_[current_stack_depth_] = std::move(*trace_event);
handle->event_index = ++current_stack_depth_;
handle->chunk_index = kMagicChunkIndex;
handle->chunk_seq = sink_id_;
return true;
}
return false;
}
void TrackEventThreadLocalEventSink::ResetIncrementalStateIfNeeded( void TrackEventThreadLocalEventSink::ResetIncrementalStateIfNeeded(
base::trace_event::TraceEvent* trace_event) { base::trace_event::TraceEvent* trace_event) {
bool explicit_timestamp = bool explicit_timestamp =
trace_event->flags() & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP; trace_event->flags() & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP;
// We access |incremental_state_reset_id_| atomically but racily. It's OK if // We access |incremental_state_reset_id_| atomically but racily. It's OK if
// we don't notice the reset request immediately, as long as we will notice // we don't notice the reset request immediately, as long as we will notice
// and service it eventually. // and service it eventually.
...@@ -248,6 +215,17 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent( ...@@ -248,6 +215,17 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent(
// Each event's updates to InternedData are flushed at the end of // Each event's updates to InternedData are flushed at the end of
// AddTraceEvent(). // AddTraceEvent().
DCHECK(pending_interning_updates_.empty()); DCHECK(pending_interning_updates_.empty());
char phase = trace_event->phase();
// Split COMPLETE events into BEGIN/END pairs. We write the BEGIN here, and
// the END in UpdateDuration().
if (phase == TRACE_EVENT_PHASE_COMPLETE) {
phase = TRACE_EVENT_PHASE_BEGIN;
}
bool is_end_of_a_complete_event = !handle && phase == TRACE_EVENT_PHASE_END;
uint32_t flags = trace_event->flags(); uint32_t flags = trace_event->flags();
bool copy_strings = flags & TRACE_EVENT_FLAG_COPY; bool copy_strings = flags & TRACE_EVENT_FLAG_COPY;
bool is_java_event = flags & TRACE_EVENT_FLAG_JAVA_STRING_LITERALS; bool is_java_event = flags & TRACE_EVENT_FLAG_JAVA_STRING_LITERALS;
...@@ -255,10 +233,14 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent( ...@@ -255,10 +233,14 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent(
const char* category_name = const char* category_name =
TraceLog::GetCategoryGroupName(trace_event->category_group_enabled()); TraceLog::GetCategoryGroupName(trace_event->category_group_enabled());
InterningIndexEntry interned_category = InterningIndexEntry interned_category{};
interned_event_categories_.LookupOrAdd(category_name); // Don't write the category for END events that were split from a COMPLETE
// event to save trace size.
if (!is_end_of_a_complete_event) {
interned_category = interned_event_categories_.LookupOrAdd(category_name);
}
InterningIndexEntry interned_name; InterningIndexEntry interned_name{};
const size_t kMaxSize = base::trace_event::TraceArguments::kMaxSize; const size_t kMaxSize = base::trace_event::TraceArguments::kMaxSize;
InterningIndexEntry interned_annotation_names[kMaxSize] = { InterningIndexEntry interned_annotation_names[kMaxSize] = {
InterningIndexEntry{}}; InterningIndexEntry{}};
...@@ -273,70 +255,73 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent( ...@@ -273,70 +255,73 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent(
// Don't write the name or arguments for END events that were split from a // Don't write the name or arguments for END events that were split from a
// COMPLETE event to save trace size. // COMPLETE event to save trace size.
const char* trace_event_name = trace_event->name(); const char* trace_event_name = trace_event->name();
if (copy_strings) { if (!is_end_of_a_complete_event) {
if (!is_java_event && privacy_filtering_enabled_) { if (copy_strings) {
trace_event_name = kPrivacyFiltered; if (!is_java_event && privacy_filtering_enabled_) {
interned_name = interned_event_names_.LookupOrAdd(trace_event_name); trace_event_name = kPrivacyFiltered;
} else { interned_name = interned_event_names_.LookupOrAdd(trace_event_name);
interned_name =
interned_event_names_.LookupOrAdd(std::string(trace_event_name));
for (size_t i = 0;
i < trace_event->arg_size() && trace_event->arg_name(i); ++i) {
interned_annotation_names[i] = interned_annotation_names_.LookupOrAdd(
std::string(trace_event->arg_name(i)));
}
}
} else {
interned_name = interned_event_names_.LookupOrAdd(trace_event->name());
// TODO(eseckler): Remove special handling of typed events here once we
// support them in TRACE_EVENT macros.
if (flags & TRACE_EVENT_FLAG_TYPED_PROTO_ARGS) {
if (trace_event->arg_size() == 2u) {
DCHECK_EQ(strcmp(category_name, kTaskExecutionEventCategory), 0);
DCHECK(strcmp(trace_event->name(), kTaskExecutionEventNames[0]) == 0 ||
strcmp(trace_event->name(), kTaskExecutionEventNames[1]) == 0 ||
strcmp(trace_event->name(), kTaskExecutionEventNames[2]) == 0);
// Double argument task execution event (src_file, src_func).
DCHECK_EQ(trace_event->arg_type(0), TRACE_VALUE_TYPE_STRING);
DCHECK_EQ(trace_event->arg_type(1), TRACE_VALUE_TYPE_STRING);
src_file = trace_event->arg_value(0).as_string;
src_func = trace_event->arg_value(1).as_string;
} else { } else {
// arg_size == 1 enforced by the maximum number of parameter == 2. interned_name =
DCHECK_EQ(trace_event->arg_size(), 1u); interned_event_names_.LookupOrAdd(std::string(trace_event_name));
for (size_t i = 0;
i < trace_event->arg_size() && trace_event->arg_name(i); ++i) {
interned_annotation_names[i] = interned_annotation_names_.LookupOrAdd(
std::string(trace_event->arg_name(i)));
}
}
} else {
interned_name = interned_event_names_.LookupOrAdd(trace_event->name());
// TODO(eseckler): Remove special handling of typed events here once we
// support them in TRACE_EVENT macros.
if (trace_event->arg_type(0) == TRACE_VALUE_TYPE_STRING) { if (flags & TRACE_EVENT_FLAG_TYPED_PROTO_ARGS) {
// Single argument task execution event (src_file). if (trace_event->arg_size() == 2u) {
DCHECK_EQ(strcmp(category_name, kTaskExecutionEventCategory), 0); DCHECK_EQ(strcmp(category_name, kTaskExecutionEventCategory), 0);
DCHECK( DCHECK(
strcmp(trace_event->name(), kTaskExecutionEventNames[0]) == 0 || strcmp(trace_event->name(), kTaskExecutionEventNames[0]) == 0 ||
strcmp(trace_event->name(), kTaskExecutionEventNames[1]) == 0 || strcmp(trace_event->name(), kTaskExecutionEventNames[1]) == 0 ||
strcmp(trace_event->name(), kTaskExecutionEventNames[2]) == 0); strcmp(trace_event->name(), kTaskExecutionEventNames[2]) == 0);
// Double argument task execution event (src_file, src_func).
DCHECK_EQ(trace_event->arg_type(0), TRACE_VALUE_TYPE_STRING);
DCHECK_EQ(trace_event->arg_type(1), TRACE_VALUE_TYPE_STRING);
src_file = trace_event->arg_value(0).as_string; src_file = trace_event->arg_value(0).as_string;
src_func = trace_event->arg_value(1).as_string;
} else { } else {
DCHECK(trace_event->arg_type(0) == TRACE_VALUE_TYPE_CONVERTABLE); // arg_size == 1 enforced by the maximum number of parameter == 2.
DCHECK(strcmp(category_name, "log") == 0); DCHECK_EQ(trace_event->arg_size(), 1u);
DCHECK(strcmp(trace_event->name(), "LogMessage") == 0);
const base::trace_event::LogMessage* value = if (trace_event->arg_type(0) == TRACE_VALUE_TYPE_STRING) {
static_cast<base::trace_event::LogMessage*>( // Single argument task execution event (src_file).
trace_event->arg_value(0).as_convertable); DCHECK_EQ(strcmp(category_name, kTaskExecutionEventCategory), 0);
src_file = value->file(); DCHECK(
line_number = value->line_number(); strcmp(trace_event->name(), kTaskExecutionEventNames[0]) == 0 ||
log_message_body = value->message().c_str(); strcmp(trace_event->name(), kTaskExecutionEventNames[1]) == 0 ||
strcmp(trace_event->name(), kTaskExecutionEventNames[2]) == 0);
interned_log_message_body = src_file = trace_event->arg_value(0).as_string;
interned_log_message_bodies_.LookupOrAdd(value->message()); } else {
} // else DCHECK_EQ(trace_event->arg_type(0), TRACE_VALUE_TYPE_CONVERTABLE);
} // else DCHECK(strcmp(category_name, "log") == 0);
interned_source_location = interned_source_locations_.LookupOrAdd( DCHECK(strcmp(trace_event->name(), "LogMessage") == 0);
std::make_tuple(src_file, src_func, line_number)); const base::trace_event::LogMessage* value =
} else if (!privacy_filtering_enabled_) { static_cast<base::trace_event::LogMessage*>(
for (size_t i = 0; trace_event->arg_value(0).as_convertable);
i < trace_event->arg_size() && trace_event->arg_name(i); ++i) { src_file = value->file();
interned_annotation_names[i] = line_number = value->line_number();
interned_annotation_names_.LookupOrAdd(trace_event->arg_name(i)); log_message_body = value->message().c_str();
interned_log_message_body =
interned_log_message_bodies_.LookupOrAdd(value->message());
} // else
} // else
interned_source_location = interned_source_locations_.LookupOrAdd(
std::make_tuple(src_file, src_func, line_number));
} else if (!privacy_filtering_enabled_) {
for (size_t i = 0;
i < trace_event->arg_size() && trace_event->arg_name(i); ++i) {
interned_annotation_names[i] =
interned_annotation_names_.LookupOrAdd(trace_event->arg_name(i));
}
} }
} }
} }
...@@ -390,7 +375,9 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent( ...@@ -390,7 +375,9 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent(
} }
// TODO(eseckler): Split comma-separated category strings. // TODO(eseckler): Split comma-separated category strings.
track_event->add_category_iids(interned_category.id); if (interned_category.id) {
track_event->add_category_iids(interned_category.id);
}
if (interned_log_message_body.id) { if (interned_log_message_body.id) {
auto* log_message = track_event->set_log_message(); auto* log_message = track_event->set_log_message();
...@@ -405,9 +392,11 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent( ...@@ -405,9 +392,11 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent(
auto* legacy_event = track_event->set_legacy_event(); auto* legacy_event = track_event->set_legacy_event();
legacy_event->set_name_iid(interned_name.id); // TODO(eseckler): Set name on |track_event| instead.
if (interned_name.id) {
legacy_event->set_name_iid(interned_name.id);
}
char phase = trace_event->phase();
legacy_event->set_phase(phase); legacy_event->set_phase(phase);
if (phase == TRACE_EVENT_PHASE_COMPLETE) { if (phase == TRACE_EVENT_PHASE_COMPLETE) {
...@@ -546,6 +535,14 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent( ...@@ -546,6 +535,14 @@ void TrackEventThreadLocalEventSink::PrepareTrackEvent(
interned_source_locations_.Clear(); interned_source_locations_.Clear();
interned_log_message_bodies_.Clear(); interned_log_message_bodies_.Clear();
} }
#if defined(OS_ANDROID)
// Send the original trace event to atrace. Since we send COMPLETE events,
// make sure not to send the END events that were split from a COMPLETE event.
if (!is_end_of_a_complete_event) {
trace_event->SendToATrace();
}
#endif
} }
void TrackEventThreadLocalEventSink::EmitStoredInternedData( void TrackEventThreadLocalEventSink::EmitStoredInternedData(
...@@ -591,39 +588,22 @@ void TrackEventThreadLocalEventSink::EmitStoredInternedData( ...@@ -591,39 +588,22 @@ void TrackEventThreadLocalEventSink::EmitStoredInternedData(
} }
void TrackEventThreadLocalEventSink::UpdateDuration( void TrackEventThreadLocalEventSink::UpdateDuration(
const unsigned char* category_group_enabled,
const char* name,
base::trace_event::TraceEventHandle handle, base::trace_event::TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const base::TimeTicks& now, const base::TimeTicks& now,
const base::ThreadTicks& thread_now, const base::ThreadTicks& thread_now,
base::trace_event::ThreadInstructionCount thread_instruction_now) { base::trace_event::ThreadInstructionCount thread_instruction_now) {
if (!handle.event_index || handle.chunk_index != kMagicChunkIndex || base::trace_event::TraceEvent new_trace_event(
handle.chunk_seq != sink_id_) { thread_id, now, thread_now, thread_instruction_now, TRACE_EVENT_PHASE_END,
return; category_group_enabled, name, trace_event_internal::kGlobalScope,
} trace_event_internal::kNoId /* id */,
trace_event_internal::kNoId /* bind_id */, nullptr,
DCHECK_GE(current_stack_depth_, 1u); explicit_timestamps ? TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP
// During trace shutdown, as the list of enabled categories are : TRACE_EVENT_FLAG_NONE);
// non-monotonically shut down, there's the possibility that events higher in AddTraceEvent(&new_trace_event, nullptr, [](perfetto::EventContext) {});
// the stack will have their category disabled prior to events lower in the
// stack, hence we get misaligned here. In this case, as we know we're
// shutting down, we leave the events unfinished.
if (handle.event_index != current_stack_depth_) {
DCHECK(handle.event_index > 0 &&
handle.event_index < current_stack_depth_ &&
!base::trace_event::TraceLog::GetInstance()->IsEnabled());
current_stack_depth_ = std::min(
current_stack_depth_, static_cast<uint32_t>(handle.event_index - 1));
return;
}
current_stack_depth_--;
complete_event_stack_[current_stack_depth_].UpdateDuration(
now, thread_now, thread_instruction_now);
AddTraceEvent(&complete_event_stack_[current_stack_depth_], nullptr,
[](perfetto::EventContext) {});
#if defined(OS_ANDROID)
complete_event_stack_[current_stack_depth_].SendToATrace();
#endif
} }
void TrackEventThreadLocalEventSink::Flush() { void TrackEventThreadLocalEventSink::Flush() {
......
...@@ -71,12 +71,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink ...@@ -71,12 +71,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink
// (e.g. interning index entries and a ThreadDescriptor) to be emitted again. // (e.g. interning index entries and a ThreadDescriptor) to be emitted again.
static void ClearIncrementalState(); static void ClearIncrementalState();
// Returns true if the current |trace_event| is part of a COMPLETE event
// phase. As part of this we will update any stack information to keep track
// of the information when we can pop something off the stack.
bool MaybeHandleCompleteEvent(base::trace_event::TraceEvent* trace_event,
base::trace_event::TraceEventHandle* handle);
// If we need to perform an incremental reset we will do so, and also emit all // If we need to perform an incremental reset we will do so, and also emit all
// the relevant descriptors to start a new fresh sequence. // the relevant descriptors to start a new fresh sequence.
void ResetIncrementalStateIfNeeded( void ResetIncrementalStateIfNeeded(
...@@ -99,10 +93,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink ...@@ -99,10 +93,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink
void AddTraceEvent(base::trace_event::TraceEvent* trace_event, void AddTraceEvent(base::trace_event::TraceEvent* trace_event,
base::trace_event::TraceEventHandle* handle, base::trace_event::TraceEventHandle* handle,
TrackEventArgumentFunction arg_func) { TrackEventArgumentFunction arg_func) {
if (MaybeHandleCompleteEvent(trace_event, handle)) {
return;
}
ResetIncrementalStateIfNeeded(trace_event); ResetIncrementalStateIfNeeded(trace_event);
auto trace_packet = trace_writer_->NewTracePacket(); auto trace_packet = trace_writer_->NewTracePacket();
...@@ -117,7 +107,11 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink ...@@ -117,7 +107,11 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink
} }
void UpdateDuration( void UpdateDuration(
const unsigned char* category_group_enabled,
const char* name,
base::trace_event::TraceEventHandle handle, base::trace_event::TraceEventHandle handle,
int thread_id,
bool explicit_timestamps,
const base::TimeTicks& now, const base::TimeTicks& now,
const base::ThreadTicks& thread_now, const base::ThreadTicks& thread_now,
base::trace_event::ThreadInstructionCount thread_instruction_now); base::trace_event::ThreadInstructionCount thread_instruction_now);
...@@ -168,9 +162,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink ...@@ -168,9 +162,6 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink
perfetto::protos::pbzero::ThreadDescriptor::ChromeThreadType thread_type_ = perfetto::protos::pbzero::ThreadDescriptor::ChromeThreadType thread_type_ =
perfetto::protos::pbzero::ThreadDescriptor::CHROME_THREAD_UNSPECIFIED; perfetto::protos::pbzero::ThreadDescriptor::CHROME_THREAD_UNSPECIFIED;
base::trace_event::TraceEvent complete_event_stack_[kMaxCompleteEventDepth];
uint32_t current_stack_depth_ = 0;
const bool privacy_filtering_enabled_; const bool privacy_filtering_enabled_;
std::unique_ptr<perfetto::StartupTraceWriter> trace_writer_; std::unique_ptr<perfetto::StartupTraceWriter> trace_writer_;
......
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