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

perfetto: Collect and emit stats for proto2json conversion

To aid debugging data loss issues.

Bug: 914092, 1008424
Change-Id: I06b91acd892970b6bba251c1893247debf61b16a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1835577Reviewed-by: default avatarStephen Nusko <nuskos@chromium.org>
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702030}
parent be9e81d8
...@@ -359,6 +359,17 @@ void JSONTraceExporter::SetTraceStatsMetadata( ...@@ -359,6 +359,17 @@ void JSONTraceExporter::SetTraceStatsMetadata(
metadata_->SetDictionary("perfetto_trace_stats", std::move(dict)); metadata_->SetDictionary("perfetto_trace_stats", std::move(dict));
} }
void JSONTraceExporter::AddMetadata(const std::string& entry_name,
std::unique_ptr<base::Value> value) {
if (!metadata_filter_predicate_.is_null() &&
!metadata_filter_predicate_.Run(entry_name)) {
metadata_->SetString(entry_name, kStrippedArgument);
return;
}
metadata_->Set(entry_name, std::move(value));
}
JSONTraceExporter::ScopedJSONTraceEventAppender JSONTraceExporter::ScopedJSONTraceEventAppender
JSONTraceExporter::AddTraceEvent(const char* name, JSONTraceExporter::AddTraceEvent(const char* name,
const char* categories, const char* categories,
......
...@@ -255,6 +255,9 @@ class JSONTraceExporter { ...@@ -255,6 +255,9 @@ class JSONTraceExporter {
int32_t pid, int32_t pid,
int32_t tid); int32_t tid);
void AddMetadata(const std::string& entry_name,
std::unique_ptr<base::Value> value);
private: private:
// Used by the implementation to ensure the proper separators exist between // Used by the implementation to ensure the proper separators exist between
// trace events in the array. // trace events in the array.
......
...@@ -94,17 +94,17 @@ void TrackEventJSONExporter::ProcessPackets( ...@@ -94,17 +94,17 @@ void TrackEventJSONExporter::ProcessPackets(
// and wait for the first state_clear before emitting anything. // and wait for the first state_clear before emitting anything.
if (packet.trusted_packet_sequence_id() != if (packet.trusted_packet_sequence_id() !=
current_state_->trusted_packet_sequence_id) { current_state_->trusted_packet_sequence_id) {
stats_.sequences_seen++;
StartNewState(packet.trusted_packet_sequence_id(), StartNewState(packet.trusted_packet_sequence_id(),
packet.incremental_state_cleared()); packet.incremental_state_cleared());
} else if (packet.incremental_state_cleared()) { } else if (packet.incremental_state_cleared()) {
stats_.incremental_state_resets++;
ResetIncrementalState(); ResetIncrementalState();
} else if (packet.previous_packet_dropped()) { } else if (packet.previous_packet_dropped()) {
// If we've lost packets we can no longer trust any timestamp data and // If we've lost packets we can no longer trust any timestamp data and
// other state which might have been dropped. We will keep skipping events // other state which might have been dropped. We will keep skipping events
// until we start a new sequence. // until we start a new sequence.
LOG_IF(ERROR, current_state_->incomplete) stats_.packets_with_previous_packet_dropped++;
<< "Previous packet was dropped. Skipping TraceEvents until reset or "
<< "new sequence.";
current_state_->incomplete = true; current_state_->incomplete = true;
} }
...@@ -136,6 +136,7 @@ void TrackEventJSONExporter::ProcessPackets( ...@@ -136,6 +136,7 @@ void TrackEventJSONExporter::ProcessPackets(
} }
if (!has_more) { if (!has_more) {
EmitThreadDescriptorIfNeeded(); EmitThreadDescriptorIfNeeded();
EmitStats();
} }
} }
...@@ -227,6 +228,7 @@ void TrackEventJSONExporter::HandleInternedData( ...@@ -227,6 +228,7 @@ void TrackEventJSONExporter::HandleInternedData(
// InternedData is only emitted on sequences with incremental state. // InternedData is only emitted on sequences with incremental state.
if (current_state_->incomplete) { if (current_state_->incomplete) {
stats_.packets_dropped_invalid_incremental_state++;
return; return;
} }
...@@ -311,6 +313,7 @@ void TrackEventJSONExporter::HandleProcessDescriptor( ...@@ -311,6 +313,7 @@ void TrackEventJSONExporter::HandleProcessDescriptor(
// ProcessDescriptor is only emitted on sequences with incremental state. // ProcessDescriptor is only emitted on sequences with incremental state.
if (current_state_->incomplete) { if (current_state_->incomplete) {
stats_.packets_dropped_invalid_incremental_state++;
return; return;
} }
...@@ -388,6 +391,7 @@ void TrackEventJSONExporter::HandleThreadDescriptor( ...@@ -388,6 +391,7 @@ void TrackEventJSONExporter::HandleThreadDescriptor(
// ThreadDescriptor is only emitted on sequences with incremental state. // ThreadDescriptor is only emitted on sequences with incremental state.
if (current_state_->incomplete) { if (current_state_->incomplete) {
stats_.packets_dropped_invalid_incremental_state++;
return; return;
} }
...@@ -472,6 +476,7 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) { ...@@ -472,6 +476,7 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) {
// TrackEvents need incremental state. // TrackEvents need incremental state.
if (current_state_->incomplete) { if (current_state_->incomplete) {
stats_.packets_dropped_invalid_incremental_state++;
return; return;
} }
...@@ -500,12 +505,8 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) { ...@@ -500,12 +505,8 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) {
const std::string joined_categories = base::JoinString(all_categories, ","); const std::string joined_categories = base::JoinString(all_categories, ",");
DCHECK(track.has_legacy_event()) << "required field legacy_event missing"; DCHECK(track.has_legacy_event()) << "required field legacy_event missing";
auto maybe_builder = auto builder =
HandleLegacyEvent(track.legacy_event(), joined_categories, timestamp_us); HandleLegacyEvent(track.legacy_event(), joined_categories, timestamp_us);
if (!maybe_builder) {
return;
}
auto& builder = *maybe_builder;
if (thread_time_us) { if (thread_time_us) {
builder.AddThreadTimestamp(*thread_time_us); builder.AddThreadTimestamp(*thread_time_us);
...@@ -532,7 +533,12 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) { ...@@ -532,7 +533,12 @@ void TrackEventJSONExporter::HandleTrackEvent(const ChromeTracePacket& packet) {
void TrackEventJSONExporter::HandleStreamingProfilePacket( void TrackEventJSONExporter::HandleStreamingProfilePacket(
const perfetto::protos::StreamingProfilePacket& profile_packet) { const perfetto::protos::StreamingProfilePacket& profile_packet) {
if (current_state_->incomplete || !ShouldOutputTraceEvents()) { if (current_state_->incomplete) {
stats_.packets_dropped_invalid_incremental_state++;
return;
}
if (!ShouldOutputTraceEvents()) {
return; return;
} }
...@@ -701,7 +707,7 @@ void TrackEventJSONExporter::HandleTaskExecution( ...@@ -701,7 +707,7 @@ void TrackEventJSONExporter::HandleTaskExecution(
} }
} }
base::Optional<JSONTraceExporter::ScopedJSONTraceEventAppender> JSONTraceExporter::ScopedJSONTraceEventAppender
TrackEventJSONExporter::HandleLegacyEvent(const TrackEvent::LegacyEvent& event, TrackEventJSONExporter::HandleLegacyEvent(const TrackEvent::LegacyEvent& event,
const std::string& categories, const std::string& categories,
int64_t timestamp_us) { int64_t timestamp_us) {
...@@ -791,4 +797,17 @@ TrackEventJSONExporter::HandleLegacyEvent(const TrackEvent::LegacyEvent& event, ...@@ -791,4 +797,17 @@ TrackEventJSONExporter::HandleLegacyEvent(const TrackEvent::LegacyEvent& event,
builder.AddFlags(flags, id, event.id_scope()); builder.AddFlags(flags, id, event.id_scope());
return builder; return builder;
} }
void TrackEventJSONExporter::EmitStats() {
auto value = std::make_unique<base::DictionaryValue>();
value->SetInteger("sequences_seen", stats_.sequences_seen);
value->SetInteger("incremental_state_resets",
stats_.incremental_state_resets);
value->SetInteger("packets_dropped_invalid_incremental_state",
stats_.packets_dropped_invalid_incremental_state);
value->SetInteger("packets_with_previous_packet_dropped",
stats_.packets_with_previous_packet_dropped);
AddMetadata("json_exporter_stats", std::move(value));
}
} // namespace tracing } // namespace tracing
...@@ -154,17 +154,27 @@ class TrackEventJSONExporter : public JSONTraceExporter { ...@@ -154,17 +154,27 @@ class TrackEventJSONExporter : public JSONTraceExporter {
ArgumentBuilder* args_builder); ArgumentBuilder* args_builder);
// Used to handle the LegacyEvent message found inside the TrackEvent proto. // Used to handle the LegacyEvent message found inside the TrackEvent proto.
base::Optional<ScopedJSONTraceEventAppender> HandleLegacyEvent( ScopedJSONTraceEventAppender HandleLegacyEvent(
const perfetto::protos::TrackEvent_LegacyEvent& event, const perfetto::protos::TrackEvent_LegacyEvent& event,
const std::string& categories, const std::string& categories,
int64_t timestamp_us); int64_t timestamp_us);
void EmitStats();
// Tracks all the interned state in the current sequence. // Tracks all the interned state in the current sequence.
std::unique_ptr<ProducerWriterState> current_state_; std::unique_ptr<ProducerWriterState> current_state_;
// Tracks out-of-order seqeuence data. // Tracks out-of-order seqeuence data.
std::map<uint32_t, UnorderedProducerWriterState> unordered_state_data_; std::map<uint32_t, UnorderedProducerWriterState> unordered_state_data_;
struct Stats {
int sequences_seen = 0;
int incremental_state_resets = 0;
int packets_dropped_invalid_incremental_state = 0;
int packets_with_previous_packet_dropped = 0;
};
Stats stats_;
DISALLOW_COPY_AND_ASSIGN(TrackEventJSONExporter); DISALLOW_COPY_AND_ASSIGN(TrackEventJSONExporter);
}; };
......
...@@ -414,7 +414,8 @@ TEST_F(TrackEventJsonExporterTest, EmptyProcessDescriptor) { ...@@ -414,7 +414,8 @@ TEST_F(TrackEventJsonExporterTest, EmptyProcessDescriptor) {
FinalizePackets(trace_packet_protos); FinalizePackets(trace_packet_protos);
// No traceEvents or data was emitted but a process descriptor without extra // No traceEvents or data was emitted but a process descriptor without extra
// data should just be an empty array and not cause crashes. // data should just be an empty array and not cause crashes.
EXPECT_EQ("{\"traceEvents\":[]}", unparsed_trace_data_); EXPECT_THAT(unparsed_trace_data_,
testing::StartsWith("{\"traceEvents\":[],"));
} }
TEST_F(TrackEventJsonExporterTest, SortIndexProcessDescriptor) { TEST_F(TrackEventJsonExporterTest, SortIndexProcessDescriptor) {
...@@ -575,7 +576,8 @@ TEST_F(TrackEventJsonExporterTest, EmptyThreadDescriptor) { ...@@ -575,7 +576,8 @@ TEST_F(TrackEventJsonExporterTest, EmptyThreadDescriptor) {
FinalizePackets(trace_packet_protos); FinalizePackets(trace_packet_protos);
// No traceEvents or data was emitted but a thread descriptor should be an // No traceEvents or data was emitted but a thread descriptor should be an
// empty array and not cause crashes. // empty array and not cause crashes.
EXPECT_EQ("{\"traceEvents\":[]}", unparsed_trace_data_); EXPECT_THAT(unparsed_trace_data_,
testing::StartsWith("{\"traceEvents\":[],"));
} }
TEST_F(TrackEventJsonExporterTest, SortIndexThreadDescriptor) { TEST_F(TrackEventJsonExporterTest, SortIndexThreadDescriptor) {
...@@ -715,7 +717,8 @@ TEST_F(TrackEventJsonExporterTest, JustInternedData) { ...@@ -715,7 +717,8 @@ TEST_F(TrackEventJsonExporterTest, JustInternedData) {
&trace_packet_protos); &trace_packet_protos);
FinalizePackets(trace_packet_protos); FinalizePackets(trace_packet_protos);
// Interned data by itself does not call any trace events to be emitted. // Interned data by itself does not call any trace events to be emitted.
EXPECT_EQ("{\"traceEvents\":[]}", unparsed_trace_data_); EXPECT_THAT(unparsed_trace_data_,
testing::StartsWith("{\"traceEvents\":[],"));
} }
TEST_F(TrackEventJsonExporterTest, LegacyEventBasicTest) { TEST_F(TrackEventJsonExporterTest, LegacyEventBasicTest) {
...@@ -1758,10 +1761,11 @@ TEST_F(TrackEventJsonExporterTest, TestTraceStats) { ...@@ -1758,10 +1761,11 @@ TEST_F(TrackEventJsonExporterTest, TestTraceStats) {
// base class. See json_trace_exporter_unittest for a more complete test. // base class. See json_trace_exporter_unittest for a more complete test.
trace_packet_protos.back().mutable_trace_stats(); trace_packet_protos.back().mutable_trace_stats();
FinalizePackets(trace_packet_protos); FinalizePackets(trace_packet_protos);
EXPECT_TRUE(base::StartsWith(unparsed_trace_data_,
"{\"traceEvents\":[]," EXPECT_THAT(unparsed_trace_data_, testing::StartsWith("{\"traceEvents\":[],"
"\"metadata\":{\"perfetto_trace_stats\":{\"", "\"metadata\":{"));
base::CompareCase::SENSITIVE)); EXPECT_THAT(unparsed_trace_data_,
testing::HasSubstr("\"perfetto_trace_stats\":{\""));
} }
TEST_F(TrackEventJsonExporterTest, ComplexLongSequenceWithDroppedPackets) { TEST_F(TrackEventJsonExporterTest, ComplexLongSequenceWithDroppedPackets) {
......
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