Commit 5cfb8f4a authored by Eric Seckler's avatar Eric Seckler Committed by Commit Bot

tracing: Support thread instructions on begin/end events

Currently, we only support thread instruction delta values on
PHASE_COMPLETE events. Since we'll soon replace complete events
(at least on TrackEvent proto level) with begin/end event pairs, this
patch adds support for emitting absolute thread instruction count
values on begin/end events.

Also ensures that we write sensible timestamps for all metadata events
in TraceLog.

Bug: 925589
Change-Id: Ie01339aefb3d148457f51057e0722c4506dda82f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1729262
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Reviewed-by: default avatarSami Kyöstilä <skyostil@chromium.org>
Cr-Commit-Position: refs/heads/master@{#682840}
parent 87b0ad82
...@@ -7,12 +7,14 @@ ...@@ -7,12 +7,14 @@
#include <stdint.h> #include <stdint.h>
#include "base/base_export.h"
namespace base { namespace base {
namespace trace_event { namespace trace_event {
// Represents the number of instructions that were retired between two samples // Represents the number of instructions that were retired between two samples
// of a thread's performance counters. // of a thread's performance counters.
class ThreadInstructionDelta { class BASE_EXPORT ThreadInstructionDelta {
public: public:
constexpr ThreadInstructionDelta() : delta_(0) {} constexpr ThreadInstructionDelta() : delta_(0) {}
explicit constexpr ThreadInstructionDelta(int64_t delta) : delta_(delta) {} explicit constexpr ThreadInstructionDelta(int64_t delta) : delta_(delta) {}
...@@ -25,7 +27,7 @@ class ThreadInstructionDelta { ...@@ -25,7 +27,7 @@ class ThreadInstructionDelta {
// Uses the system's performance counters in order to measure the number of // Uses the system's performance counters in order to measure the number of
// instructions that have been retired on the current thread. // instructions that have been retired on the current thread.
class ThreadInstructionCount { class BASE_EXPORT ThreadInstructionCount {
public: public:
// Returns true if the platform supports hardware retired instruction // Returns true if the platform supports hardware retired instruction
// counters. // counters.
......
...@@ -214,6 +214,12 @@ void TraceEvent::AppendAsJSON( ...@@ -214,6 +214,12 @@ void TraceEvent::AppendAsJSON(
StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64); StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
} }
// Output ticount if thread_instruction_count is valid.
if (!thread_instruction_count_.is_null()) {
int64_t thread_instructions = thread_instruction_count_.ToInternalValue();
StringAppendF(out, ",\"ticount\":%" PRId64, thread_instructions);
}
// Output async tts marker field if flag is set. // Output async tts marker field if flag is set.
if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) { if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
StringAppendF(out, ", \"use_async_tts\":1"); StringAppendF(out, ", \"use_async_tts\":1");
......
...@@ -114,8 +114,11 @@ void InitializeMetadataEvent(TraceEvent* trace_event, ...@@ -114,8 +114,11 @@ void InitializeMetadataEvent(TraceEvent* trace_event,
return; return;
TraceArguments args(arg_name, value); TraceArguments args(arg_name, value);
trace_event->Reset(thread_id, TimeTicks(), ThreadTicks(), base::TimeTicks now = TRACE_TIME_TICKS_NOW();
ThreadInstructionCount(), TRACE_EVENT_PHASE_METADATA, ThreadTicks thread_now = ThreadNow();
ThreadInstructionCount thread_instruction_count = ThreadInstructionNow();
trace_event->Reset(thread_id, now, thread_now, thread_instruction_count,
TRACE_EVENT_PHASE_METADATA,
CategoryRegistry::kCategoryMetadata->state_ptr(), CategoryRegistry::kCategoryMetadata->state_ptr(),
metadata_name, metadata_name,
trace_event_internal::kGlobalScope, // scope trace_event_internal::kGlobalScope, // scope
......
...@@ -584,6 +584,11 @@ void JSONTraceExporter::ScopedJSONTraceEventAppender::AddThreadTimestamp( ...@@ -584,6 +584,11 @@ void JSONTraceExporter::ScopedJSONTraceEventAppender::AddThreadTimestamp(
out_->AppendF(",\"tts\":%" PRId64, thread_timestamp); out_->AppendF(",\"tts\":%" PRId64, thread_timestamp);
} }
void JSONTraceExporter::ScopedJSONTraceEventAppender::AddThreadInstructionCount(
int64_t thread_instruction_count) {
out_->AppendF(",\"ticount\":%" PRId64, thread_instruction_count);
}
void JSONTraceExporter::ScopedJSONTraceEventAppender::AddThreadInstructionDelta( void JSONTraceExporter::ScopedJSONTraceEventAppender::AddThreadInstructionDelta(
int64_t thread_instruction_delta) { int64_t thread_instruction_delta) {
out_->AppendF(",\"tidelta\":%" PRId64, thread_instruction_delta); out_->AppendF(",\"tidelta\":%" PRId64, thread_instruction_delta);
......
...@@ -166,6 +166,7 @@ class JSONTraceExporter { ...@@ -166,6 +166,7 @@ class JSONTraceExporter {
void AddDuration(int64_t duration); void AddDuration(int64_t duration);
void AddThreadDuration(int64_t thread_duration); void AddThreadDuration(int64_t thread_duration);
void AddThreadTimestamp(int64_t thread_timestamp); void AddThreadTimestamp(int64_t thread_timestamp);
void AddThreadInstructionCount(int64_t thread_instruction_count);
void AddThreadInstructionDelta(int64_t thread_instruction_delta); void AddThreadInstructionDelta(int64_t thread_instruction_delta);
void AddBindId(uint64_t bind_id); void AddBindId(uint64_t bind_id);
// A set of bit flags for this trace event, along with a |scope|. |scope| is // A set of bit flags for this trace event, along with a |scope|. |scope| is
......
...@@ -204,6 +204,21 @@ base::Optional<int64_t> TrackEventJSONExporter::ComputeThreadTimeUs( ...@@ -204,6 +204,21 @@ base::Optional<int64_t> TrackEventJSONExporter::ComputeThreadTimeUs(
} }
} }
base::Optional<int64_t> TrackEventJSONExporter::ComputeThreadInstructionCount(
const TrackEvent& event) {
switch (event.thread_instruction_count_case()) {
case TrackEvent::kThreadInstructionCountAbsolute:
return event.thread_instruction_count_absolute();
case TrackEvent::kThreadInstructionCountDelta:
DCHECK_NE(current_state_->thread_instruction_count, -1);
current_state_->thread_instruction_count +=
event.thread_instruction_count_delta();
return current_state_->thread_instruction_count;
case TrackEvent::THREAD_INSTRUCTION_COUNT_NOT_SET:
return base::nullopt;
}
}
void TrackEventJSONExporter::HandleInternedData( void TrackEventJSONExporter::HandleInternedData(
const ChromeTracePacket& packet) { const ChromeTracePacket& packet) {
DCHECK(packet.has_interned_data()); DCHECK(packet.has_interned_data());
...@@ -380,6 +395,8 @@ void TrackEventJSONExporter::HandleThreadDescriptor( ...@@ -380,6 +395,8 @@ void TrackEventJSONExporter::HandleThreadDescriptor(
current_state_->tid = thread.tid(); current_state_->tid = thread.tid();
current_state_->time_us = thread.reference_timestamp_us(); current_state_->time_us = thread.reference_timestamp_us();
current_state_->thread_time_us = thread.reference_thread_time_us(); current_state_->thread_time_us = thread.reference_thread_time_us();
current_state_->thread_instruction_count =
thread.reference_thread_instruction_count();
// If we aren't outputting traceEvents then we don't need to look at the // If we aren't outputting traceEvents then we don't need to look at the
// metadata that might need to be emitted. // metadata that might need to be emitted.
...@@ -468,6 +485,8 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) { ...@@ -468,6 +485,8 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) {
int64_t timestamp_us = ComputeTimeUs(track); int64_t timestamp_us = ComputeTimeUs(track);
DCHECK_NE(timestamp_us, -1); DCHECK_NE(timestamp_us, -1);
base::Optional<int64_t> thread_time_us = ComputeThreadTimeUs(track); base::Optional<int64_t> thread_time_us = ComputeThreadTimeUs(track);
base::Optional<int64_t> thread_instruction_count =
ComputeThreadInstructionCount(track);
std::vector<base::StringPiece> all_categories; std::vector<base::StringPiece> all_categories;
all_categories.reserve(track.category_iids().size()); all_categories.reserve(track.category_iids().size());
...@@ -490,6 +509,10 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) { ...@@ -490,6 +509,10 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) {
builder.AddThreadTimestamp(*thread_time_us); builder.AddThreadTimestamp(*thread_time_us);
} }
if (thread_instruction_count) {
builder.AddThreadInstructionCount(*thread_instruction_count);
}
// Now we add args from both |task_execution| and |debug_annotations|. Recall // Now we add args from both |task_execution| and |debug_annotations|. Recall
// that |args_builder| must run its deconstructer before any other fields in // that |args_builder| must run its deconstructer before any other fields in
// traceEvents are added. Therefore do not do anything below this comment but // traceEvents are added. Therefore do not do anything below this comment but
......
...@@ -58,6 +58,7 @@ class TrackEventJSONExporter : public JSONTraceExporter { ...@@ -58,6 +58,7 @@ class TrackEventJSONExporter : public JSONTraceExporter {
int32_t tid = -1; int32_t tid = -1;
int64_t time_us = -1; int64_t time_us = -1;
int64_t thread_time_us = -1; int64_t thread_time_us = -1;
int64_t thread_instruction_count = -1;
// We only want to add metadata events about the process or threads once. // We only want to add metadata events about the process or threads once.
// This is to prevent duplicate events in the json since the packets // This is to prevent duplicate events in the json since the packets
...@@ -125,6 +126,8 @@ class TrackEventJSONExporter : public JSONTraceExporter { ...@@ -125,6 +126,8 @@ class TrackEventJSONExporter : public JSONTraceExporter {
int64_t ComputeTimeUs(const perfetto::protos::TrackEvent& event); int64_t ComputeTimeUs(const perfetto::protos::TrackEvent& event);
base::Optional<int64_t> ComputeThreadTimeUs( base::Optional<int64_t> ComputeThreadTimeUs(
const perfetto::protos::TrackEvent& event); const perfetto::protos::TrackEvent& event);
base::Optional<int64_t> ComputeThreadInstructionCount(
const perfetto::protos::TrackEvent& event);
// Gather all the interned strings of different types. // Gather all the interned strings of different types.
void HandleInternedData(const perfetto::protos::ChromeTracePacket& packet); void HandleInternedData(const perfetto::protos::ChromeTracePacket& packet);
......
...@@ -320,6 +320,23 @@ void TrackEventThreadLocalEventSink::AddTraceEvent( ...@@ -320,6 +320,23 @@ void TrackEventThreadLocalEventSink::AddTraceEvent(
} }
} }
if (!trace_event->thread_instruction_count().is_null()) {
// Thread instruction counts are never user-provided, but COMPLETE events
// may get reordered, so we can still observe counts that are lower. Emit
// those as absolute counts, since we don't support negative deltas.
if (last_thread_instruction_count_.ToInternalValue() >
trace_event->thread_instruction_count().ToInternalValue()) {
track_event->set_thread_instruction_count_absolute(
trace_event->thread_instruction_count().ToInternalValue());
} else {
track_event->set_thread_instruction_count_delta(
(trace_event->thread_instruction_count() -
last_thread_instruction_count_)
.ToInternalValue());
last_thread_instruction_count_ = trace_event->thread_instruction_count();
}
}
// TODO(eseckler): Split comma-separated category strings. // TODO(eseckler): Split comma-separated category strings.
track_event->add_category_iids(interned_category.id); track_event->add_category_iids(interned_category.id);
...@@ -576,13 +593,29 @@ void TrackEventThreadLocalEventSink::EmitThreadDescriptor( ...@@ -576,13 +593,29 @@ void TrackEventThreadLocalEventSink::EmitThreadDescriptor(
last_thread_time_ = ThreadNow(); last_thread_time_ = ThreadNow();
} else { } else {
// Thread timestamp is never user-provided. // Thread timestamp is never user-provided.
DCHECK(trace_event->thread_timestamp() <= ThreadNow()); DCHECK_LE(trace_event->thread_timestamp(), ThreadNow());
last_thread_time_ = trace_event->thread_timestamp(); last_thread_time_ = trace_event->thread_timestamp();
} }
thread_descriptor->set_reference_timestamp_us( thread_descriptor->set_reference_timestamp_us(
last_timestamp_.since_origin().InMicroseconds()); last_timestamp_.since_origin().InMicroseconds());
thread_descriptor->set_reference_thread_time_us( thread_descriptor->set_reference_thread_time_us(
last_thread_time_.since_origin().InMicroseconds()); last_thread_time_.since_origin().InMicroseconds());
if (base::trace_event::ThreadInstructionCount::IsSupported()) {
if (!trace_event || trace_event->thread_instruction_count().is_null()) {
last_thread_instruction_count_ =
base::trace_event::ThreadInstructionCount::Now();
} else {
// Thread instruction count is never user-provided.
DCHECK_LE(
trace_event->thread_instruction_count().ToInternalValue(),
base::trace_event::ThreadInstructionCount::Now().ToInternalValue());
last_thread_instruction_count_ = trace_event->thread_instruction_count();
}
thread_descriptor->set_reference_thread_instruction_count(
last_thread_instruction_count_.ToInternalValue());
}
// TODO(eseckler): Fill in remaining fields in ThreadDescriptor. // TODO(eseckler): Fill in remaining fields in ThreadDescriptor.
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/threading/thread_id_name_manager.h" #include "base/threading/thread_id_name_manager.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/trace_event/thread_instruction_count.h"
#include "services/tracing/public/cpp/perfetto/interning_index.h" #include "services/tracing/public/cpp/perfetto/interning_index.h"
#include "services/tracing/public/cpp/perfetto/thread_local_event_sink.h" #include "services/tracing/public/cpp/perfetto/thread_local_event_sink.h"
#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h" #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
...@@ -80,6 +81,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink ...@@ -80,6 +81,7 @@ class COMPONENT_EXPORT(TRACING_CPP) TrackEventThreadLocalEventSink
uint32_t last_incremental_state_reset_id_ = 0; uint32_t last_incremental_state_reset_id_ = 0;
base::TimeTicks last_timestamp_; base::TimeTicks last_timestamp_;
base::ThreadTicks last_thread_time_; base::ThreadTicks last_thread_time_;
base::trace_event::ThreadInstructionCount last_thread_instruction_count_;
int process_id_; int process_id_;
int thread_id_; int thread_id_;
std::string thread_name_; std::string thread_name_;
......
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