processor: Support TrackDescriptor's parent_uuid + pid/tid reuse
Refactors tokenization and parsing of TrackDescriptors so that:
- Only a single ProcessDescriptor track is supported per process.
- Only a single ThreadDescriptor track is supported per thread.
- Such a process/thread track is merged with slice-type system events
into a single track.
- Other tracks (e.g. async tracks) can be associated with a thread
or process using the "parent_uuid" field.
- pid/tid reuse (i.e. new process/thread spawns with same pid/tid
after old process/thread terminates) is detected based on changing
uuids of Process/ThreadDescriptor tracks.
To accomplish this, tokenization now only makes reservations for tracks
without actually inserting anything into the track table - since
TrackDescriptors may appear in any order in the file, and we cannot
know the track's type/context until we see its parent's descriptor.
During parsing, the reservations will be resolved and inserted into the
track table. If the uuid of a process's or thread's track changes, we
assume that the pid/tid of the process/thread was reused.
Change-Id: Iec1d019db211773eb15ee517ae0dac1ce87553c9
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 04e3a5d..acc6e93 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -517,6 +517,12 @@
TraceFormatWriter* writer) {
const auto& slices = storage->slice_table();
for (uint32_t i = 0; i < slices.row_count(); ++i) {
+ // Skip slices with empty category - these are ftrace/system slices that
+ // were also imported into the raw table and will be exported from there by
+ // trace_to_text.
+ if (slices.category()[i] == kNullStringId)
+ continue;
+
Json::Value event;
event["ts"] = Json::Int64(slices.ts()[i] / 1000);
event["cat"] = GetNonNullString(storage, slices.category()[i]);
@@ -551,14 +557,11 @@
uint32_t track_row = *track_table.id().IndexOf(TrackId{track_id});
auto track_args_id = track_table.source_arg_set_id()[track_row];
- if (!track_args_id)
- continue;
- const auto& track_args = args_builder.GetArgs(*track_args_id);
- bool legacy_chrome_track = track_args["source"].asString() == "chrome";
- if (!track_args.isMember("source") ||
- (!legacy_chrome_track &&
- track_args["source"].asString() != "descriptor")) {
- continue;
+ const Json::Value* track_args = nullptr;
+ bool legacy_chrome_track = false;
+ if (track_args_id) {
+ track_args = &args_builder.GetArgs(*track_args_id);
+ legacy_chrome_track = (*track_args)["source"].asString() == "chrome";
}
const auto& thread_table = storage->thread_table();
@@ -646,12 +649,13 @@
}
writer->WriteCommonEvent(event);
} else if (!legacy_chrome_track ||
- (legacy_chrome_track && track_args.isMember("source_id"))) {
+ (legacy_chrome_track && track_args->isMember("source_id"))) {
// Async event slice.
auto opt_process_row = process_track.id().IndexOf(TrackId{track_id});
if (legacy_chrome_track) {
- // Legacy async tracks are always process-associated.
+ // Legacy async tracks are always process-associated and have args.
PERFETTO_DCHECK(opt_process_row);
+ PERFETTO_DCHECK(track_args);
uint32_t upid = process_track.upid()[*opt_process_row];
event["pid"] = static_cast<int32_t>(process_table.pid()[upid]);
event["tid"] = legacy_tid
@@ -660,16 +664,16 @@
// Preserve original event IDs for legacy tracks. This is so that e.g.
// memory dump IDs show up correctly in the JSON trace.
- PERFETTO_DCHECK(track_args.isMember("source_id"));
- PERFETTO_DCHECK(track_args.isMember("source_id_is_process_scoped"));
- PERFETTO_DCHECK(track_args.isMember("source_scope"));
+ PERFETTO_DCHECK(track_args->isMember("source_id"));
+ PERFETTO_DCHECK(track_args->isMember("source_id_is_process_scoped"));
+ PERFETTO_DCHECK(track_args->isMember("source_scope"));
uint64_t source_id =
- static_cast<uint64_t>(track_args["source_id"].asInt64());
- std::string source_scope = track_args["source_scope"].asString();
+ static_cast<uint64_t>((*track_args)["source_id"].asInt64());
+ std::string source_scope = (*track_args)["source_scope"].asString();
if (!source_scope.empty())
event["scope"] = source_scope;
bool source_id_is_process_scoped =
- track_args["source_id_is_process_scoped"].asBool();
+ (*track_args)["source_id_is_process_scoped"].asBool();
if (source_id_is_process_scoped) {
event["id2"]["local"] = PrintUint64(source_id);
} else {
@@ -730,6 +734,7 @@
}
} else {
// Global or process-scoped instant event.
+ PERFETTO_DCHECK(legacy_chrome_track);
PERFETTO_DCHECK(duration_ns == 0);
// Use "I" instead of "i" phase for backwards-compat with old consumers.
event["ph"] = "I";
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index e572d67..a0050df 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -119,8 +119,7 @@
const char* kName = "name";
UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -166,8 +165,7 @@
const char* kName = "name";
UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -225,13 +223,14 @@
EXPECT_EQ(event["args"]["name"].asString(), kName);
}
-TEST_F(ExportJsonTest, WrongTrackTypeIgnored) {
+TEST_F(ExportJsonTest, SystemEventsIgnored) {
constexpr int64_t kCookie = 22;
TrackId track = context_.track_tracker->InternAndroidAsyncTrack(
/*name=*/0, /*upid=*/0, kCookie);
context_.args_tracker->Flush(); // Flush track args.
- StringId cat_id = context_.storage->InternString("cat");
+ // System events have no category.
+ StringId cat_id = kNullStringId;
StringId name_id = context_.storage->InternString("name");
context_.storage->mutable_slice_table()->Insert(
{0, 0, track.value, cat_id, name_id, 0, 0, 0});
@@ -406,8 +405,7 @@
const char* kSrc = "source_file.cc";
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -451,8 +449,7 @@
TraceStorage* storage = context_.storage.get();
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = storage->InternString(base::StringView(kCategory));
StringId name_id = storage->InternString(base::StringView(kName));
@@ -501,8 +498,7 @@
double kValues[] = {1.234, 2.345};
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -550,8 +546,7 @@
uint64_t kValue1 = std::numeric_limits<uint64_t>::max();
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -595,8 +590,7 @@
int kValues[] = {123, 234};
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -643,8 +637,7 @@
int kValues[] = {123, 234};
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -691,8 +684,7 @@
const char* kName = "name";
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -761,8 +753,7 @@
const char* kName = "name";
UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
@@ -1241,8 +1232,7 @@
TEST_F(ExportJsonTest, ArgumentFilter) {
UniqueTid utid = context_.process_tracker->GetOrCreateThread(0);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView("cat"));
@@ -1354,8 +1344,7 @@
const char* kName = "name";
UniqueTid utid = context_.process_tracker->GetOrCreateThread(kThreadID);
- TrackId track =
- context_.track_tracker->GetOrCreateDescriptorTrackForThread(utid);
+ TrackId track = context_.track_tracker->InternThreadTrack(utid);
context_.args_tracker->Flush(); // Flush track args.
StringId cat_id = context_.storage->InternString(base::StringView(kCategory));
StringId name_id = context_.storage->InternString(base::StringView(kName));
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index ac04c4f..424c7d2 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -786,7 +786,6 @@
Tokenize();
EXPECT_CALL(*process_, UpdateThread(16, 15))
- .Times(3)
.WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
@@ -867,7 +866,6 @@
Tokenize();
EXPECT_CALL(*process_, UpdateThread(16, 15))
- .Times(3)
.WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
@@ -1003,7 +1001,6 @@
Tokenize();
EXPECT_CALL(*process_, UpdateThread(16, 15))
- .Times(5)
.WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
@@ -1234,6 +1231,7 @@
auto* packet = trace_.add_packet();
packet->set_trusted_packet_sequence_id(1);
packet->set_incremental_state_cleared(true);
+ packet->set_timestamp(1000000);
auto* track_desc = packet->set_track_descriptor();
track_desc->set_uuid(1234);
track_desc->set_name("Thread track 1");
@@ -1244,6 +1242,7 @@
{
auto* packet = trace_.add_packet();
packet->set_trusted_packet_sequence_id(1);
+ packet->set_timestamp(1000000);
auto* track_desc = packet->set_track_descriptor();
track_desc->set_uuid(5678);
track_desc->set_name("Async track 1");
@@ -1297,6 +1296,7 @@
auto* packet = trace_.add_packet();
packet->set_trusted_packet_sequence_id(2);
packet->set_incremental_state_cleared(true);
+ packet->set_timestamp(1000000);
auto* track_desc = packet->set_track_descriptor();
track_desc->set_uuid(4321);
track_desc->set_name("Thread track 2");
@@ -1305,12 +1305,6 @@
thread_desc->set_tid(17);
}
{
- auto* packet = trace_.add_packet();
- packet->set_trusted_packet_sequence_id(2);
- auto* track_desc = packet->set_track_descriptor();
- track_desc->set_uuid(5678); // "Async track 1" defined on sequence 1.
- }
- {
// Async event completed on "Async track 1".
auto* packet = trace_.add_packet();
packet->set_trusted_packet_sequence_id(2);
@@ -1361,21 +1355,9 @@
.WillOnce(Return(11));
EXPECT_CALL(*storage_, InternString(base::StringView("Thread track 2")))
.WillOnce(Return(12));
- EXPECT_CALL(*storage_, InternString(base::StringView("")))
- .WillOnce(Return(0));
Tokenize();
- // First track is "Thread track 1"; second is "Async track 1", third is
- // "Thread track 2".
- EXPECT_EQ(storage_->track_table().row_count(), 3u);
- EXPECT_EQ(storage_->track_table().name()[0], 10u); // "Thread track 1"
- EXPECT_EQ(storage_->track_table().name()[1], 11u); // "Async track 1"
- EXPECT_EQ(storage_->track_table().name()[2], 12u); // "Thread track 2"
- EXPECT_EQ(storage_->thread_track_table().row_count(), 2u);
- EXPECT_EQ(storage_->thread_track_table().utid()[0], 1u);
- EXPECT_EQ(storage_->thread_track_table().utid()[1], 2u);
-
InSequence in_sequence; // Below slices should be sorted by timestamp.
EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
@@ -1406,9 +1388,15 @@
context_.sorter->ExtractEventsForced();
- // Track tables shouldn't have changed.
+ // First track is "Thread track 1"; second is "Async track 1", third is
+ // "Thread track 2".
EXPECT_EQ(storage_->track_table().row_count(), 3u);
+ EXPECT_EQ(storage_->track_table().name()[0], 10u); // "Thread track 1"
+ EXPECT_EQ(storage_->track_table().name()[1], 11u); // "Async track 1"
+ EXPECT_EQ(storage_->track_table().name()[2], 12u); // "Thread track 2"
EXPECT_EQ(storage_->thread_track_table().row_count(), 2u);
+ EXPECT_EQ(storage_->thread_track_table().utid()[0], 1u);
+ EXPECT_EQ(storage_->thread_track_table().utid()[1], 2u);
EXPECT_EQ(storage_->virtual_track_slices().slice_count(), 1u);
EXPECT_EQ(storage_->virtual_track_slices().slice_ids()[0], 0u);
@@ -1575,7 +1563,6 @@
Tokenize();
EXPECT_CALL(*process_, UpdateThread(16, 15))
- .Times(2)
.WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
@@ -1678,10 +1665,8 @@
Tokenize();
EXPECT_CALL(*process_, UpdateThread(16, 15))
- .Times(2)
.WillRepeatedly(Return(1));
EXPECT_CALL(*process_, UpdateThread(17, 15))
- .Times(2)
.WillRepeatedly(Return(2));
tables::ThreadTable::Row t1(16);
@@ -1842,7 +1827,6 @@
Tokenize();
EXPECT_CALL(*process_, UpdateThread(16, 15))
- .Times(2)
.WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
@@ -1972,7 +1956,7 @@
Tokenize();
- EXPECT_CALL(*process_, UpdateThread(16, 15)).WillOnce(Return(1));
+ EXPECT_CALL(*process_, UpdateThread(16, 15)).WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
row.upid = 1u;
@@ -2051,7 +2035,7 @@
Tokenize();
- EXPECT_CALL(*process_, UpdateThread(16, 15)).WillOnce(Return(1));
+ EXPECT_CALL(*process_, UpdateThread(16, 15)).WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
row.upid = 1u;
@@ -2136,7 +2120,7 @@
Tokenize();
- EXPECT_CALL(*process_, UpdateThread(16, 15)).WillOnce(Return(1));
+ EXPECT_CALL(*process_, UpdateThread(16, 15)).WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
row.upid = 1u;
@@ -2230,7 +2214,7 @@
Tokenize();
- EXPECT_CALL(*process_, UpdateThread(16, 15)).WillOnce(Return(1));
+ EXPECT_CALL(*process_, UpdateThread(16, 15)).WillRepeatedly(Return(1));
tables::ThreadTable::Row row(16);
row.upid = 1u;
diff --git a/src/trace_processor/importers/proto/track_event_module.cc b/src/trace_processor/importers/proto/track_event_module.cc
index 2fd7cd1..1bbbebd 100644
--- a/src/trace_processor/importers/proto/track_event_module.cc
+++ b/src/trace_processor/importers/proto/track_event_module.cc
@@ -14,9 +14,14 @@
* limitations under the License.
*/
#include "src/trace_processor/importers/proto/track_event_module.h"
-#include "perfetto/base/build_config.h"
-#include "src/trace_processor/timestamped_trace_piece.h"
+#include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
+#include "src/trace_processor/trace_processor_context.h"
+#include "src/trace_processor/track_tracker.h"
+
+#include "protos/perfetto/config/data_source_config.pbzero.h"
#include "protos/perfetto/config/trace_config.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
@@ -43,20 +48,15 @@
uint32_t field_id) {
switch (field_id) {
case TracePacket::kTrackDescriptorFieldNumber:
- tokenizer_.TokenizeTrackDescriptorPacket(state, decoder);
- return ModuleResult::Handled();
+ return tokenizer_.TokenizeTrackDescriptorPacket(state, decoder,
+ packet_timestamp);
case TracePacket::kTrackEventFieldNumber:
tokenizer_.TokenizeTrackEventPacket(state, decoder, packet,
packet_timestamp);
return ModuleResult::Handled();
case TracePacket::kThreadDescriptorFieldNumber:
- // TODO(eseckler): Remove these once Chrome has switched fully over to
- // TrackDescriptors.
- tokenizer_.TokenizeThreadDescriptorPacket(state, decoder);
- return ModuleResult::Handled();
- case TracePacket::kProcessDescriptorFieldNumber:
- tokenizer_.TokenizeProcessDescriptorPacket(decoder);
- return ModuleResult::Handled();
+ // TODO(eseckler): Remove once Chrome has switched to TrackDescriptors.
+ return tokenizer_.TokenizeThreadDescriptorPacket(state, decoder);
}
return ModuleResult::Ignored();
}
@@ -64,12 +64,28 @@
void TrackEventModule::ParsePacket(const TracePacket::Decoder& decoder,
const TimestampedTracePiece& ttp,
uint32_t field_id) {
- if (field_id == TracePacket::kTrackEventFieldNumber) {
- PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTrackEvent);
- parser_.ParseTrackEvent(
- ttp.timestamp, ttp.track_event_data->thread_timestamp,
- ttp.track_event_data->thread_instruction_count,
- ttp.track_event_data->sequence_state, decoder.track_event());
+ switch (field_id) {
+ case TracePacket::kTrackDescriptorFieldNumber:
+ PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
+ parser_.ParseTrackDescriptor(decoder.track_descriptor());
+ break;
+ case TracePacket::kTrackEventFieldNumber:
+ PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTrackEvent);
+ parser_.ParseTrackEvent(
+ ttp.timestamp, ttp.track_event_data->thread_timestamp,
+ ttp.track_event_data->thread_instruction_count,
+ ttp.track_event_data->sequence_state, decoder.track_event());
+ break;
+ case TracePacket::kProcessDescriptorFieldNumber:
+ // TODO(eseckler): Remove once Chrome has switched to TrackDescriptors.
+ PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
+ parser_.ParseProcessDescriptor(decoder.process_descriptor());
+ break;
+ case TracePacket::kThreadDescriptorFieldNumber:
+ // TODO(eseckler): Remove once Chrome has switched to TrackDescriptors.
+ PERFETTO_DCHECK(ttp.type == TimestampedTracePiece::Type::kTracePacket);
+ parser_.ParseThreadDescriptor(decoder.thread_descriptor());
+ break;
}
}
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 720db46..5d86efe 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -31,11 +31,16 @@
#include "protos/perfetto/trace/track_event/chrome_histogram_sample.pbzero.h"
#include "protos/perfetto/trace/track_event/chrome_keyed_service.pbzero.h"
#include "protos/perfetto/trace/track_event/chrome_legacy_ipc.pbzero.h"
+#include "protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/chrome_thread_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/chrome_user_event.pbzero.h"
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "protos/perfetto/trace/track_event/log_message.pbzero.h"
+#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace perfetto {
@@ -200,7 +205,143 @@
context->storage->InternString("MEDIA_PLAYER_DELEGATE"),
context->storage->InternString("EXTENSION_WORKER"),
context->storage->InternString("SUBRESOURCE_FILTER"),
- context->storage->InternString("UNFREEZABLE_FRAME")}} {}
+ context->storage->InternString("UNFREEZABLE_FRAME")}},
+ chrome_process_name_ids_{
+ {context_->storage->InternString("Unknown"),
+ context_->storage->InternString("Browser"),
+ context_->storage->InternString("Renderer"),
+ context_->storage->InternString("Utility"),
+ context_->storage->InternString("Zygote"),
+ context_->storage->InternString("SandboxHelper"),
+ context_->storage->InternString("Gpu"),
+ context_->storage->InternString("PpapiPlugin"),
+ context_->storage->InternString("PpapiBroker")}},
+ chrome_thread_name_ids_{
+ {context_->storage->InternString("ChromeUnspecified"),
+ context_->storage->InternString("CrProcessMain"),
+ context_->storage->InternString("ChromeIOThread"),
+ context_->storage->InternString("ThreadPoolBackgroundWorker&"),
+ context_->storage->InternString("ThreadPoolForegroundWorker&"),
+ context_->storage->InternString(
+ "ThreadPoolSingleThreadForegroundBlocking&"),
+ context_->storage->InternString(
+ "ThreadPoolSingleThreadBackgroundBlocking&"),
+ context_->storage->InternString("ThreadPoolService"),
+ context_->storage->InternString("Compositor"),
+ context_->storage->InternString("VizCompositorThread"),
+ context_->storage->InternString("CompositorTileWorker&"),
+ context_->storage->InternString("ServiceWorkerThread&"),
+ context_->storage->InternString("MemoryInfra"),
+ context_->storage->InternString("StackSamplingProfiler")}} {}
+
+void TrackEventParser::ParseTrackDescriptor(
+ protozero::ConstBytes track_descriptor) {
+ protos::pbzero::TrackDescriptor::Decoder decoder(track_descriptor);
+
+ // Ensure that the track and its parents are resolved. This may start a new
+ // process and/or thread (i.e. new upid/utid).
+ TrackId track_id =
+ *context_->track_tracker->GetDescriptorTrack(decoder.uuid());
+
+ if (decoder.has_process()) {
+ UniquePid upid = ParseProcessDescriptor(decoder.process());
+ if (decoder.has_chrome_process())
+ ParseChromeProcessDescriptor(upid, decoder.chrome_process());
+ }
+
+ if (decoder.has_thread()) {
+ UniqueTid utid = ParseThreadDescriptor(decoder.thread());
+ if (decoder.has_chrome_thread())
+ ParseChromeThreadDescriptor(utid, decoder.chrome_thread());
+ }
+
+ if (decoder.has_name()) {
+ auto* tracks = context_->storage->mutable_track_table();
+ StringId name_id = context_->storage->InternString(decoder.name());
+ tracks->mutable_name()->Set(*tracks->id().IndexOf(track_id), name_id);
+ }
+}
+
+UniquePid TrackEventParser::ParseProcessDescriptor(
+ protozero::ConstBytes process_descriptor) {
+ protos::pbzero::ProcessDescriptor::Decoder decoder(process_descriptor);
+ UniquePid upid = context_->process_tracker->GetOrCreateProcess(
+ static_cast<uint32_t>(decoder.pid()));
+ if (decoder.has_process_name()) {
+ // Don't override system-provided names.
+ context_->process_tracker->SetProcessNameIfUnset(
+ upid, context_->storage->InternString(decoder.process_name()));
+ }
+ // TODO(skyostil): Remove parsing for legacy chrome_process_type field.
+ if (decoder.has_chrome_process_type()) {
+ auto process_type = decoder.chrome_process_type();
+ size_t name_index =
+ static_cast<size_t>(process_type) < chrome_process_name_ids_.size()
+ ? static_cast<size_t>(process_type)
+ : 0u;
+ StringId name_id = chrome_process_name_ids_[name_index];
+ // Don't override system-provided names.
+ context_->process_tracker->SetProcessNameIfUnset(upid, name_id);
+ }
+ return upid;
+}
+
+void TrackEventParser::ParseChromeProcessDescriptor(
+ UniquePid upid,
+ protozero::ConstBytes chrome_process_descriptor) {
+ protos::pbzero::ChromeProcessDescriptor::Decoder decoder(
+ chrome_process_descriptor);
+ auto process_type = decoder.process_type();
+ size_t name_index =
+ static_cast<size_t>(process_type) < chrome_process_name_ids_.size()
+ ? static_cast<size_t>(process_type)
+ : 0u;
+ StringId name_id = chrome_process_name_ids_[name_index];
+ // Don't override system-provided names.
+ context_->process_tracker->SetProcessNameIfUnset(upid, name_id);
+}
+
+UniqueTid TrackEventParser::ParseThreadDescriptor(
+ protozero::ConstBytes thread_descriptor) {
+ protos::pbzero::ThreadDescriptor::Decoder decoder(thread_descriptor);
+ UniqueTid utid = context_->process_tracker->UpdateThread(
+ static_cast<uint32_t>(decoder.tid()),
+ static_cast<uint32_t>(decoder.pid()));
+ StringId name_id = kNullStringId;
+ if (decoder.has_thread_name()) {
+ name_id = context_->storage->InternString(decoder.thread_name());
+ } else if (decoder.has_chrome_thread_type()) {
+ // TODO(skyostil): Remove parsing for legacy chrome_thread_type field.
+ auto thread_type = decoder.chrome_thread_type();
+ size_t name_index =
+ static_cast<size_t>(thread_type) < chrome_thread_name_ids_.size()
+ ? static_cast<size_t>(thread_type)
+ : 0u;
+ name_id = chrome_thread_name_ids_[name_index];
+ }
+ if (name_id != kNullStringId) {
+ // Don't override system-provided names.
+ context_->process_tracker->SetThreadNameIfUnset(utid, name_id);
+ }
+ return utid;
+}
+
+void TrackEventParser::ParseChromeThreadDescriptor(
+ UniqueTid utid,
+ protozero::ConstBytes chrome_thread_descriptor) {
+ protos::pbzero::ChromeThreadDescriptor::Decoder decoder(
+ chrome_thread_descriptor);
+ if (!decoder.has_thread_type())
+ return;
+
+ auto thread_type = decoder.thread_type();
+ size_t name_index =
+ static_cast<size_t>(thread_type) < chrome_thread_name_ids_.size()
+ ? static_cast<size_t>(thread_type)
+ : 0u;
+ StringId name_id = chrome_thread_name_ids_[name_index];
+ context_->process_tracker->SetThreadNameIfUnset(utid, name_id);
+}
void TrackEventParser::ParseTrackEvent(
int64_t ts,
@@ -353,7 +494,7 @@
utid = procs->UpdateThread(tid, pid);
upid = storage->thread_table().upid()[*utid];
- track_id = track_tracker->GetOrCreateDescriptorTrackForThread(*utid);
+ track_id = track_tracker->InternThreadTrack(*utid);
} else {
track_id = track_tracker->GetOrCreateDefaultDescriptorTrack();
}
diff --git a/src/trace_processor/importers/proto/track_event_parser.h b/src/trace_processor/importers/proto/track_event_parser.h
index a0a42c7..1787f0f 100644
--- a/src/trace_processor/importers/proto/track_event_parser.h
+++ b/src/trace_processor/importers/proto/track_event_parser.h
@@ -39,11 +39,19 @@
public:
explicit TrackEventParser(TraceProcessorContext* context);
+ void ParseTrackDescriptor(protozero::ConstBytes);
+ UniquePid ParseProcessDescriptor(protozero::ConstBytes);
+ UniqueTid ParseThreadDescriptor(protozero::ConstBytes);
+
void ParseTrackEvent(int64_t ts,
int64_t tts,
int64_t ticount,
PacketSequenceStateGeneration*,
protozero::ConstBytes);
+
+ private:
+ void ParseChromeProcessDescriptor(UniquePid upid, protozero::ConstBytes);
+ void ParseChromeThreadDescriptor(UniqueTid utid, protozero::ConstBytes);
void ParseLegacyEventAsRawEvent(
int64_t ts,
int64_t tts,
@@ -80,7 +88,6 @@
void ParseChromeHistogramSample(protozero::ConstBytes chrome_keyed_service,
ArgsTracker::BoundInserter* inserter);
- private:
TraceProcessorContext* context_;
const StringId task_file_name_args_key_id_;
@@ -117,6 +124,8 @@
const StringId chrome_histogram_sample_sample_args_key_id_;
std::array<StringId, 38> chrome_legacy_ipc_class_ids_;
+ std::array<StringId, 9> chrome_process_name_ids_;
+ std::array<StringId, 14> chrome_thread_name_ids_;
};
} // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index 4b03008..0c3ea93 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -41,20 +41,12 @@
namespace trace_processor {
TrackEventTokenizer::TrackEventTokenizer(TraceProcessorContext* context)
- : context_(context),
- process_name_ids_{{context_->storage->InternString("Unknown"),
- context_->storage->InternString("Browser"),
- context_->storage->InternString("Renderer"),
- context_->storage->InternString("Utility"),
- context_->storage->InternString("Zygote"),
- context_->storage->InternString("SandboxHelper"),
- context_->storage->InternString("Gpu"),
- context_->storage->InternString("PpapiPlugin"),
- context_->storage->InternString("PpapiBroker")}} {}
+ : context_(context) {}
-void TrackEventTokenizer::TokenizeTrackDescriptorPacket(
+ModuleResult TrackEventTokenizer::TokenizeTrackDescriptorPacket(
PacketSequenceState* state,
- const protos::pbzero::TracePacket::Decoder& packet_decoder) {
+ const protos::pbzero::TracePacket::Decoder& packet_decoder,
+ int64_t packet_timestamp) {
auto track_descriptor_field = packet_decoder.track_descriptor();
protos::pbzero::TrackDescriptor::Decoder track_descriptor_decoder(
track_descriptor_field.data, track_descriptor_field.size);
@@ -62,37 +54,7 @@
if (!track_descriptor_decoder.has_uuid()) {
PERFETTO_ELOG("TrackDescriptor packet without uuid");
context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
- return;
- }
-
- base::Optional<UniquePid> upid;
- base::Optional<UniqueTid> utid;
-
- if (track_descriptor_decoder.has_process()) {
- auto process_descriptor_field = track_descriptor_decoder.process();
- protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
- process_descriptor_field.data, process_descriptor_field.size);
-
- upid = TokenizeProcessDescriptor(process_descriptor_decoder);
-
- if (track_descriptor_decoder.has_chrome_process()) {
- auto chrome_process_descriptor_field =
- track_descriptor_decoder.chrome_process();
- protos::pbzero::ChromeProcessDescriptor::Decoder
- chrome_process_descriptor_decoder(
- chrome_process_descriptor_field.data,
- chrome_process_descriptor_field.size);
-
- auto process_type = chrome_process_descriptor_decoder.process_type();
- size_t name_index =
- static_cast<size_t>(process_type) < process_name_ids_.size()
- ? static_cast<size_t>(process_type)
- : 0u;
- StringId name = process_name_ids_[name_index];
-
- // Don't override system-provided names.
- context_->process_tracker->SetProcessNameIfUnset(*upid, name);
- }
+ return ModuleResult::Handled();
}
if (track_descriptor_decoder.has_thread()) {
@@ -100,72 +62,57 @@
protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
thread_descriptor_field.data, thread_descriptor_field.size);
- utid = TokenizeThreadDescriptor(state, thread_descriptor_decoder);
- upid = *context_->storage->thread_table().upid()[*utid];
-
- if (track_descriptor_decoder.has_chrome_thread()) {
- auto chrome_thread_descriptor_field =
- track_descriptor_decoder.chrome_thread();
- protos::pbzero::ChromeThreadDescriptor::Decoder
- chrome_thread_descriptor_decoder(chrome_thread_descriptor_field.data,
- chrome_thread_descriptor_field.size);
-
- TokenizeChromeThreadDescriptor(thread_descriptor_decoder.pid(),
- thread_descriptor_decoder.tid(),
- chrome_thread_descriptor_decoder);
+ if (!thread_descriptor_decoder.has_pid() ||
+ !thread_descriptor_decoder.has_tid()) {
+ PERFETTO_ELOG(
+ "No pid or tid in ThreadDescriptor for track with uuid %" PRIu64,
+ track_descriptor_decoder.uuid());
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return ModuleResult::Handled();
}
+
+ if (state->IsIncrementalStateValid()) {
+ TokenizeThreadDescriptor(state, thread_descriptor_decoder);
+ }
+
+ context_->track_tracker->ReserveDescriptorThreadTrack(
+ track_descriptor_decoder.uuid(), track_descriptor_decoder.parent_uuid(),
+ static_cast<uint32_t>(thread_descriptor_decoder.pid()),
+ static_cast<uint32_t>(thread_descriptor_decoder.tid()),
+ packet_timestamp);
+ } else if (track_descriptor_decoder.has_process()) {
+ auto process_descriptor_field = track_descriptor_decoder.process();
+ protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
+ process_descriptor_field.data, process_descriptor_field.size);
+
+ if (!process_descriptor_decoder.has_pid()) {
+ PERFETTO_ELOG("No pid in ProcessDescriptor for track with uuid %" PRIu64,
+ track_descriptor_decoder.uuid());
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return ModuleResult::Handled();
+ }
+
+ context_->track_tracker->ReserveDescriptorProcessTrack(
+ track_descriptor_decoder.uuid(),
+ static_cast<uint32_t>(process_descriptor_decoder.pid()),
+ packet_timestamp);
+ } else {
+ context_->track_tracker->ReserveDescriptorChildTrack(
+ track_descriptor_decoder.uuid(),
+ track_descriptor_decoder.parent_uuid());
}
- StringId name_id =
- context_->storage->InternString(track_descriptor_decoder.name());
-
- context_->track_tracker->UpdateDescriptorTrack(
- track_descriptor_decoder.uuid(), name_id, upid, utid);
+ // Let ProtoTraceTokenizer forward the packet to the parser.
+ return ModuleResult::Ignored();
}
-void TrackEventTokenizer::TokenizeProcessDescriptorPacket(
- const protos::pbzero::TracePacket::Decoder& packet_decoder) {
- protos::pbzero::ProcessDescriptor::Decoder process_descriptor_decoder(
- packet_decoder.process_descriptor());
- TokenizeProcessDescriptor(process_descriptor_decoder);
-}
-
-UniquePid TrackEventTokenizer::TokenizeProcessDescriptor(
- const protos::pbzero::ProcessDescriptor::Decoder&
- process_descriptor_decoder) {
- UniquePid upid = context_->process_tracker->GetOrCreateProcess(
- static_cast<uint32_t>(process_descriptor_decoder.pid()));
-
- if (process_descriptor_decoder.has_process_name()) {
- // Don't override system-provided names.
- context_->process_tracker->SetProcessNameIfUnset(
- upid, context_->storage->InternString(
- process_descriptor_decoder.process_name()));
- }
-
- // TODO(skyostil): Remove parsing for legacy chrome_process_type field.
- if (process_descriptor_decoder.has_chrome_process_type()) {
- auto process_type = process_descriptor_decoder.chrome_process_type();
- size_t name_index =
- static_cast<size_t>(process_type) < process_name_ids_.size()
- ? static_cast<size_t>(process_type)
- : 0u;
- StringId name = process_name_ids_[name_index];
-
- // Don't override system-provided names.
- context_->process_tracker->SetProcessNameIfUnset(upid, name);
- }
-
- return upid;
-}
-
-void TrackEventTokenizer::TokenizeThreadDescriptorPacket(
+ModuleResult TrackEventTokenizer::TokenizeThreadDescriptorPacket(
PacketSequenceState* state,
const protos::pbzero::TracePacket::Decoder& packet_decoder) {
if (PERFETTO_UNLIKELY(!packet_decoder.has_trusted_packet_sequence_id())) {
PERFETTO_ELOG("ThreadDescriptor packet without trusted_packet_sequence_id");
context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
- return;
+ return ModuleResult::Handled();
}
// TrackEvents will be ignored while incremental state is invalid. As a
@@ -175,161 +122,29 @@
// the first subsequent descriptor after incremental state is cleared.
if (!state->IsIncrementalStateValid()) {
context_->storage->IncrementStats(stats::tokenizer_skipped_packets);
- return;
+ return ModuleResult::Handled();
}
auto thread_descriptor_field = packet_decoder.thread_descriptor();
protos::pbzero::ThreadDescriptor::Decoder thread_descriptor_decoder(
thread_descriptor_field.data, thread_descriptor_field.size);
TokenizeThreadDescriptor(state, thread_descriptor_decoder);
+
+ // Let ProtoTraceTokenizer forward the packet to the parser.
+ return ModuleResult::Ignored();
}
-UniqueTid TrackEventTokenizer::TokenizeThreadDescriptor(
+void TrackEventTokenizer::TokenizeThreadDescriptor(
PacketSequenceState* state,
const protos::pbzero::ThreadDescriptor::Decoder&
thread_descriptor_decoder) {
- UniqueTid utid = context_->process_tracker->UpdateThread(
- static_cast<uint32_t>(thread_descriptor_decoder.tid()),
- static_cast<uint32_t>(thread_descriptor_decoder.pid()));
-
// TODO(eseckler): Remove support for legacy thread descriptor-based default
// tracks and delta timestamps.
- if (state->IsIncrementalStateValid()) {
- state->SetThreadDescriptor(
- thread_descriptor_decoder.pid(), thread_descriptor_decoder.tid(),
- thread_descriptor_decoder.reference_timestamp_us() * 1000,
- thread_descriptor_decoder.reference_thread_time_us() * 1000,
- thread_descriptor_decoder.reference_thread_instruction_count());
- }
-
- base::StringView name;
- if (thread_descriptor_decoder.has_thread_name()) {
- name = thread_descriptor_decoder.thread_name();
- } else if (thread_descriptor_decoder.has_chrome_thread_type()) {
- // TODO(skyostil): Remove parsing for legacy chrome_thread_type field.
- using protos::pbzero::ThreadDescriptor;
- switch (thread_descriptor_decoder.chrome_thread_type()) {
- case ThreadDescriptor::CHROME_THREAD_MAIN:
- name = "CrProcessMain";
- break;
- case ThreadDescriptor::CHROME_THREAD_IO:
- name = "ChromeIOThread";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_FG_WORKER:
- name = "ThreadPoolForegroundWorker&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_BG_WORKER:
- name = "ThreadPoolBackgroundWorker&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_FB_BLOCKING:
- name = "ThreadPoolSingleThreadForegroundBlocking&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_BG_BLOCKING:
- name = "ThreadPoolSingleThreadBackgroundBlocking&";
- break;
- case ThreadDescriptor::CHROME_THREAD_POOL_SERVICE:
- name = "ThreadPoolService";
- break;
- case ThreadDescriptor::CHROME_THREAD_COMPOSITOR_WORKER:
- name = "CompositorTileWorker&";
- break;
- case ThreadDescriptor::CHROME_THREAD_COMPOSITOR:
- name = "Compositor";
- break;
- case ThreadDescriptor::CHROME_THREAD_VIZ_COMPOSITOR:
- name = "VizCompositorThread";
- break;
- case ThreadDescriptor::CHROME_THREAD_SERVICE_WORKER:
- name = "ServiceWorkerThread&";
- break;
- case ThreadDescriptor::CHROME_THREAD_MEMORY_INFRA:
- name = "MemoryInfra";
- break;
- case ThreadDescriptor::CHROME_THREAD_SAMPLING_PROFILER:
- name = "StackSamplingProfiler";
- break;
- case ThreadDescriptor::CHROME_THREAD_UNSPECIFIED:
- name = "ChromeUnspecified";
- break;
- }
- }
-
- if (!name.empty()) {
- auto thread_name_id = context_->storage->InternString(name);
- ProcessTracker* procs = context_->process_tracker.get();
- // Don't override system-provided names.
- procs->SetThreadNameIfUnset(utid, thread_name_id);
- }
-
- return utid;
-}
-
-void TrackEventTokenizer::TokenizeChromeThreadDescriptor(
- int32_t pid,
- int32_t tid,
- const protos::pbzero::ChromeThreadDescriptor::Decoder&
- thread_descriptor_decoder) {
- if (!thread_descriptor_decoder.has_thread_type())
- return;
-
- base::StringView name;
- using protos::pbzero::ChromeThreadDescriptor;
- // Thread names that end in an ampersand indicate multiple thread instances
- // (e.g., CompositorTileWorker{1,2,...}) that have been collapsed into a
- // single thread name.
- switch (thread_descriptor_decoder.thread_type()) {
- case ChromeThreadDescriptor::THREAD_MAIN:
- name = "CrProcessMain";
- break;
- case ChromeThreadDescriptor::THREAD_IO:
- name = "ChromeIOThread";
- break;
- case ChromeThreadDescriptor::THREAD_POOL_FG_WORKER:
- name = "ThreadPoolForegroundWorker&";
- break;
- case ChromeThreadDescriptor::THREAD_POOL_BG_WORKER:
- name = "ThreadPoolBackgroundWorker&";
- break;
- case ChromeThreadDescriptor::THREAD_POOL_FB_BLOCKING:
- name = "ThreadPoolSingleThreadForegroundBlocking&";
- break;
- case ChromeThreadDescriptor::THREAD_POOL_BG_BLOCKING:
- name = "ThreadPoolSingleThreadBackgroundBlocking&";
- break;
- case ChromeThreadDescriptor::THREAD_POOL_SERVICE:
- name = "ThreadPoolService";
- break;
- case ChromeThreadDescriptor::THREAD_COMPOSITOR_WORKER:
- name = "CompositorTileWorker&";
- break;
- case ChromeThreadDescriptor::THREAD_COMPOSITOR:
- name = "Compositor";
- break;
- case ChromeThreadDescriptor::THREAD_VIZ_COMPOSITOR:
- name = "VizCompositorThread";
- break;
- case ChromeThreadDescriptor::THREAD_SERVICE_WORKER:
- name = "ServiceWorkerThread&";
- break;
- case ChromeThreadDescriptor::THREAD_MEMORY_INFRA:
- name = "MemoryInfra";
- break;
- case ChromeThreadDescriptor::THREAD_SAMPLING_PROFILER:
- name = "StackSamplingProfiler";
- break;
- case ChromeThreadDescriptor::THREAD_UNSPECIFIED:
- name = "ChromeUnspecified";
- break;
- }
-
- if (!name.empty()) {
- auto thread_name_id = context_->storage->InternString(name);
- ProcessTracker* procs = context_->process_tracker.get();
- // Don't override system-provided names.
- procs->SetThreadNameIfUnset(procs->UpdateThread(static_cast<uint32_t>(tid),
- static_cast<uint32_t>(pid)),
- thread_name_id);
- }
+ state->SetThreadDescriptor(
+ thread_descriptor_decoder.pid(), thread_descriptor_decoder.tid(),
+ thread_descriptor_decoder.reference_timestamp_us() * 1000,
+ thread_descriptor_decoder.reference_thread_time_us() * 1000,
+ thread_descriptor_decoder.reference_thread_instruction_count());
}
void TrackEventTokenizer::TokenizeTrackEventPacket(
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.h b/src/trace_processor/importers/proto/track_event_tokenizer.h
index b50b564..48fdf47 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.h
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.h
@@ -19,6 +19,7 @@
#include <stdint.h>
+#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/trace_storage.h"
namespace perfetto {
@@ -42,33 +43,24 @@
public:
explicit TrackEventTokenizer(TraceProcessorContext* context);
- void TokenizeTrackDescriptorPacket(
+ ModuleResult TokenizeTrackDescriptorPacket(
+ PacketSequenceState* state,
+ const protos::pbzero::TracePacket_Decoder&,
+ int64_t packet_timestamp);
+ ModuleResult TokenizeThreadDescriptorPacket(
PacketSequenceState* state,
const protos::pbzero::TracePacket_Decoder&);
- void TokenizeProcessDescriptorPacket(
- const protos::pbzero::TracePacket_Decoder&);
- void TokenizeThreadDescriptorPacket(
- PacketSequenceState* state,
- const protos::pbzero::TracePacket_Decoder&);
- void TokenizeChromeThreadDescriptor(
- int32_t pid,
- int32_t tid,
- const protos::pbzero::ChromeThreadDescriptor_Decoder&);
void TokenizeTrackEventPacket(PacketSequenceState* state,
const protos::pbzero::TracePacket_Decoder&,
TraceBlobView* packet,
int64_t packet_timestamp);
private:
- UniqueTid TokenizeThreadDescriptor(
+ void TokenizeThreadDescriptor(
PacketSequenceState* state,
const protos::pbzero::ThreadDescriptor_Decoder&);
- UniquePid TokenizeProcessDescriptor(
- const protos::pbzero::ProcessDescriptor_Decoder&);
TraceProcessorContext* context_;
-
- std::array<StringId, 9> process_name_ids_;
};
} // namespace trace_processor
diff --git a/src/trace_processor/process_tracker.cc b/src/trace_processor/process_tracker.cc
index 20ed994..5880e12 100644
--- a/src/trace_processor/process_tracker.cc
+++ b/src/trace_processor/process_tracker.cc
@@ -161,7 +161,7 @@
}
UniquePid ProcessTracker::StartNewProcess(int64_t timestamp,
- uint32_t parent_tid,
+ base::Optional<uint32_t> parent_tid,
uint32_t pid,
StringId main_thread_name) {
pids_.erase(pid);
@@ -181,12 +181,14 @@
process_table->mutable_start_ts()->Set(upid, timestamp);
process_table->mutable_name()->Set(upid, main_thread_name);
- UniqueTid parent_utid = GetOrCreateThread(parent_tid);
- auto opt_parent_upid = thread_table->upid()[parent_utid];
- if (opt_parent_upid.has_value()) {
- process_table->mutable_parent_upid()->Set(upid, *opt_parent_upid);
- } else {
- pending_parent_assocs_.emplace_back(parent_utid, upid);
+ if (parent_tid) {
+ UniqueTid parent_utid = GetOrCreateThread(*parent_tid);
+ auto opt_parent_upid = thread_table->upid()[parent_utid];
+ if (opt_parent_upid.has_value()) {
+ process_table->mutable_parent_upid()->Set(upid, *opt_parent_upid);
+ } else {
+ pending_parent_assocs_.emplace_back(parent_utid, upid);
+ }
}
return upid;
}
diff --git a/src/trace_processor/process_tracker.h b/src/trace_processor/process_tracker.h
index d7ac808..6c9f819 100644
--- a/src/trace_processor/process_tracker.h
+++ b/src/trace_processor/process_tracker.h
@@ -79,7 +79,7 @@
// Called when a task_newtask without the CLONE_THREAD flag is observed.
// This force the tracker to start both a new UTID and a new UPID.
UniquePid StartNewProcess(int64_t timestamp,
- uint32_t parent_tid,
+ base::Optional<uint32_t> parent_tid,
uint32_t pid,
StringId main_thread_name);
diff --git a/src/trace_processor/process_tracker_unittest.cc b/src/trace_processor/process_tracker_unittest.cc
index 7a251c5..11ae675 100644
--- a/src/trace_processor/process_tracker_unittest.cc
+++ b/src/trace_processor/process_tracker_unittest.cc
@@ -59,7 +59,7 @@
TEST_F(ProcessTrackerTest, StartNewProcess) {
TraceStorage storage;
- auto upid = context.process_tracker->StartNewProcess(1000, 0, 123, 0);
+ auto upid = context.process_tracker->StartNewProcess(1000, 0u, 123, 0);
ASSERT_EQ(context.process_tracker->GetOrCreateProcess(123), upid);
ASSERT_EQ(context.storage->process_table().start_ts()[upid], 1000);
}
diff --git a/src/trace_processor/track_tracker.cc b/src/trace_processor/track_tracker.cc
index 944e674..0a35102 100644
--- a/src/trace_processor/track_tracker.cc
+++ b/src/trace_processor/track_tracker.cc
@@ -17,6 +17,7 @@
#include "src/trace_processor/track_tracker.h"
#include "src/trace_processor/args_tracker.h"
+#include "src/trace_processor/process_tracker.h"
namespace perfetto {
namespace trace_processor {
@@ -50,6 +51,18 @@
return id;
}
+TrackId TrackTracker::InternProcessTrack(UniquePid upid) {
+ auto it = process_tracks_.find(upid);
+ if (it != process_tracks_.end())
+ return it->second;
+
+ tables::ProcessTrackTable::Row row;
+ row.upid = upid;
+ auto id = context_->storage->mutable_process_track_table()->Insert(row);
+ process_tracks_[upid] = id;
+ return id;
+}
+
TrackId TrackTracker::InternFuchsiaAsyncTrack(StringId name,
int64_t correlation_id) {
auto it = fuchsia_async_tracks_.find(correlation_id);
@@ -160,150 +173,221 @@
return *chrome_global_instant_track_id_;
}
-TrackId TrackTracker::UpdateDescriptorTrack(uint64_t uuid,
- StringId name,
- base::Optional<UniquePid> upid,
- base::Optional<UniqueTid> utid) {
- auto it = descriptor_tracks_.find(uuid);
- if (it != descriptor_tracks_.end()) {
- // Update existing track for |uuid|.
- TrackId track_id = it->second;
- if (name != kNullStringId) {
- auto* track = context_->storage->mutable_track_table();
- auto row = *track->id().IndexOf(track_id);
- track->mutable_name()->Set(row, name);
- }
+void TrackTracker::ReserveDescriptorProcessTrack(uint64_t uuid,
+ uint32_t pid,
+ int64_t timestamp) {
+ DescriptorTrackReservation reservation;
+ reservation.min_timestamp = timestamp;
+ reservation.pid = pid;
-#if PERFETTO_DLOG_IS_ON()
- if (upid) {
- // Verify that upid didn't change.
- auto process_track_row =
- context_->storage->process_track_table().id().IndexOf(track_id);
- if (!process_track_row) {
- PERFETTO_DLOG("Can't update non-scoped track with uuid %" PRIu64
- " to a scoped track.",
- uuid);
- } else {
- auto old_upid =
- context_->storage->process_track_table().upid()[*process_track_row];
- if (old_upid != upid) {
- PERFETTO_DLOG("Ignoring upid change for track with uuid %" PRIu64
- " from %" PRIu32 " to %" PRIu32 ".",
- uuid, old_upid, *upid);
- }
- }
- }
+ std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+ bool inserted;
+ std::tie(it, inserted) =
+ reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
- if (utid) {
- // Verify that utid didn't change.
- auto thread_track_row =
- context_->storage->thread_track_table().id().IndexOf(track_id);
- if (!thread_track_row) {
- PERFETTO_DLOG("Can't update non-thread track with uuid %" PRIu64
- " to a thread track.",
- uuid);
- } else {
- auto old_utid =
- context_->storage->thread_track_table().utid()[*thread_track_row];
- if (old_utid != utid) {
- PERFETTO_DLOG("Ignoring utid change for track with uuid %" PRIu64
- " from %" PRIu32 " to %" PRIu32 ".",
- uuid, old_utid, *utid);
- }
- }
- }
-#endif // PERFETTO_DLOG_IS_ON()
+ if (inserted)
+ return;
- return track_id;
+ if (!it->second.IsForSameTrack(reservation)) {
+ // Process tracks should not be reassigned to a different pid later (neither
+ // should the type of the track change).
+ PERFETTO_DLOG("New track reservation for process track with uuid %" PRIu64
+ " doesn't match earlier one",
+ uuid);
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return;
}
- TrackId track_id;
-
- if (utid) {
- // Update existing track for the thread if we have previously created one
- // in GetOrCreateDescriptorTrackForThread().
- auto utid_it = descriptor_tracks_by_utid_.find(*utid);
- if (utid_it != descriptor_tracks_by_utid_.end()) {
- TrackId candidate_track_id = utid_it->second;
- // Only update this track if it hasn't been associated with a different
- // UUID already.
- auto descriptor_it = std::find_if(
- descriptor_tracks_.begin(), descriptor_tracks_.end(),
- [candidate_track_id](const std::pair<uint64_t, TrackId>& entry) {
- return entry.second == candidate_track_id;
- });
- if (descriptor_it == descriptor_tracks_.end()) {
- descriptor_tracks_[uuid] = candidate_track_id;
- context_->args_tracker->AddArg(
- TableId::kTrack, candidate_track_id.value, source_id_key_,
- source_id_key_, Variadic::Integer(static_cast<int64_t>(uuid)));
-
- return candidate_track_id;
- }
- }
-
- // New thread track.
- tables::ThreadTrackTable::Row row(name);
- row.utid = *utid;
- track_id = context_->storage->mutable_thread_track_table()->Insert(row);
- if (descriptor_tracks_by_utid_.find(*utid) ==
- descriptor_tracks_by_utid_.end()) {
- descriptor_tracks_by_utid_[*utid] = track_id;
- }
- } else if (upid) {
- // New process-scoped async track.
- tables::ProcessTrackTable::Row track(name);
- track.upid = *upid;
- track_id = context_->storage->mutable_process_track_table()->Insert(track);
- } else {
- // New global async track.
- tables::TrackTable::Row track(name);
- track_id = context_->storage->mutable_track_table()->Insert(track);
- }
-
- descriptor_tracks_[uuid] = track_id;
-
- ArgsTracker::BoundInserter inserter(context_->args_tracker.get(),
- TableId::kTrack, track_id.value);
- inserter.AddArg(source_key_, Variadic::String(descriptor_source_));
- inserter.AddArg(source_id_key_,
- Variadic::Integer(static_cast<int64_t>(uuid)));
- return track_id;
+ it->second.min_timestamp = std::min(it->second.min_timestamp, timestamp);
}
-base::Optional<TrackId> TrackTracker::GetDescriptorTrack(uint64_t uuid) const {
- auto it = descriptor_tracks_.find(uuid);
- if (it == descriptor_tracks_.end())
- return base::nullopt;
+void TrackTracker::ReserveDescriptorThreadTrack(uint64_t uuid,
+ uint64_t parent_uuid,
+ uint32_t pid,
+ uint32_t tid,
+ int64_t timestamp) {
+ DescriptorTrackReservation reservation;
+ reservation.min_timestamp = timestamp;
+ reservation.parent_uuid = parent_uuid;
+ reservation.pid = pid;
+ reservation.tid = tid;
+
+ std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+ bool inserted;
+ std::tie(it, inserted) =
+ reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
+
+ if (inserted)
+ return;
+
+ if (!it->second.IsForSameTrack(reservation)) {
+ // Thread tracks should not be reassigned to a different pid/tid later
+ // (neither should the type of the track change).
+ PERFETTO_DLOG("New track reservation for thread track with uuid %" PRIu64
+ " doesn't match earlier one",
+ uuid);
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+ return;
+ }
+
+ it->second.min_timestamp = std::min(it->second.min_timestamp, timestamp);
+}
+
+void TrackTracker::ReserveDescriptorChildTrack(uint64_t uuid,
+ uint64_t parent_uuid) {
+ DescriptorTrackReservation reservation;
+ reservation.parent_uuid = parent_uuid;
+
+ std::map<uint64_t, DescriptorTrackReservation>::iterator it;
+ bool inserted;
+ std::tie(it, inserted) =
+ reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
+
+ if (inserted || it->second.IsForSameTrack(reservation))
+ return;
+
+ // Child tracks should not be reassigned to a different parent track later
+ // (neither should the type of the track change).
+ PERFETTO_DLOG("New track reservation for child track with uuid %" PRIu64
+ " doesn't match earlier one",
+ uuid);
+ context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
+}
+
+base::Optional<TrackId> TrackTracker::GetDescriptorTrack(uint64_t uuid) {
+ auto it = resolved_descriptor_tracks_.find(uuid);
+ if (it == resolved_descriptor_tracks_.end()) {
+ auto reservation_it = reserved_descriptor_tracks_.find(uuid);
+ if (reservation_it == reserved_descriptor_tracks_.end())
+ return base::nullopt;
+ TrackId track_id = ResolveDescriptorTrack(uuid, reservation_it->second);
+ resolved_descriptor_tracks_[uuid] = track_id;
+ return track_id;
+ }
return it->second;
}
-TrackId TrackTracker::GetOrCreateDescriptorTrackForThread(UniqueTid utid) {
- auto it = descriptor_tracks_by_utid_.find(utid);
- if (it != descriptor_tracks_by_utid_.end()) {
- return it->second;
+TrackId TrackTracker::ResolveDescriptorTrack(
+ uint64_t uuid,
+ const DescriptorTrackReservation& reservation) {
+ base::Optional<TrackId> parent_track_id;
+ if (reservation.parent_uuid) {
+ // Ensure that parent track is resolved.
+ parent_track_id = GetDescriptorTrack(reservation.parent_uuid);
+ if (!parent_track_id) {
+ PERFETTO_ELOG("Unknown parent track %" PRIu64 " for track %" PRIu64,
+ reservation.parent_uuid, uuid);
+ }
}
- // TODO(eseckler): How should this track receive its name?
- tables::ThreadTrackTable::Row row(/*name=*/kNullStringId);
- row.utid = utid;
- TrackId track_id =
- context_->storage->mutable_thread_track_table()->Insert(row);
- descriptor_tracks_by_utid_[utid] = track_id;
- context_->args_tracker->AddArg(TableId::kTrack, track_id.value, source_key_,
- source_key_,
- Variadic::String(descriptor_source_));
- return track_id;
+ if (reservation.tid) {
+ UniqueTid utid = context_->process_tracker->UpdateThread(*reservation.tid,
+ *reservation.pid);
+ auto it_and_inserted =
+ descriptor_uuids_by_utid_.insert(std::make_pair<>(utid, uuid));
+ if (!it_and_inserted.second) {
+ // We already saw a another track with a different uuid for this thread.
+ // Since there should only be one descriptor track for each thread, we
+ // assume that its tid was reused. So, start a new thread.
+ uint64_t old_uuid = it_and_inserted.first->second;
+ PERFETTO_DCHECK(old_uuid != uuid); // Every track is only resolved once.
+
+ PERFETTO_DLOG("Detected tid reuse (pid: %" PRIu32 " tid: %" PRIu32
+ ") from track descriptors (old uuid: %" PRIu64
+ " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
+ *reservation.pid, *reservation.tid, old_uuid, uuid,
+ reservation.min_timestamp);
+
+ utid = context_->process_tracker->StartNewThread(
+ reservation.min_timestamp, *reservation.tid, kNullStringId);
+
+ descriptor_uuids_by_utid_[utid] = uuid;
+ }
+ return InternThreadTrack(utid);
+ }
+
+ if (reservation.pid) {
+ UniquePid upid =
+ context_->process_tracker->GetOrCreateProcess(*reservation.pid);
+ auto it_and_inserted =
+ descriptor_uuids_by_upid_.insert(std::make_pair<>(upid, uuid));
+ if (!it_and_inserted.second) {
+ // We already saw a another track with a different uuid for this process.
+ // Since there should only be one descriptor track for each process, we
+ // assume that its pid was reused. So, start a new process.
+ uint64_t old_uuid = it_and_inserted.first->second;
+ PERFETTO_DCHECK(old_uuid != uuid); // Every track is only resolved once.
+
+ PERFETTO_DLOG("Detected pid reuse (pid: %" PRIu32
+ ") from track descriptors (old uuid: %" PRIu64
+ " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
+ *reservation.pid, old_uuid, uuid,
+ reservation.min_timestamp);
+
+ upid = context_->process_tracker->StartNewProcess(
+ reservation.min_timestamp, base::nullopt, *reservation.pid,
+ kNullStringId);
+
+ descriptor_uuids_by_upid_[upid] = uuid;
+ }
+ return InternProcessTrack(upid);
+ }
+
+ base::Optional<TrackId> track_id;
+ if (parent_track_id) {
+ // If parent is a thread track, create another thread-associated track.
+ base::Optional<uint32_t> thread_track_index =
+ context_->storage->thread_track_table().id().IndexOf(*parent_track_id);
+ if (thread_track_index) {
+ auto* thread_tracks = context_->storage->mutable_thread_track_table();
+ tables::ThreadTrackTable::Row row;
+ row.utid = thread_tracks->utid()[*thread_track_index];
+ track_id = thread_tracks->Insert(row);
+ } else {
+ // If parent is a process track, create another process-associated track.
+ base::Optional<uint32_t> process_track_index =
+ context_->storage->process_track_table().id().IndexOf(
+ *parent_track_id);
+ if (process_track_index) {
+ auto* process_tracks = context_->storage->mutable_process_track_table();
+ tables::ProcessTrackTable::Row track;
+ track.upid = process_tracks->upid()[*process_track_index];
+ track_id = process_tracks->Insert(track);
+ }
+ }
+ }
+
+ // Otherwise create a global track.
+ if (!track_id) {
+ tables::TrackTable::Row track;
+ track_id = context_->storage->mutable_track_table()->Insert(track);
+ }
+
+ ArgsTracker::BoundInserter inserter(context_->args_tracker.get(),
+ TableId::kTrack, track_id->value);
+ inserter.AddArg(source_key_, Variadic::String(descriptor_source_));
+ inserter.AddArg(source_id_key_,
+ Variadic::Integer(static_cast<int64_t>(uuid)));
+
+ return *track_id;
}
TrackId TrackTracker::GetOrCreateDefaultDescriptorTrack() {
- base::Optional<TrackId> opt_track_id =
+ // If the default track was already reserved (e.g. because a producer emitted
+ // a descriptor for it) or created, resolve and return it.
+ base::Optional<TrackId> track_id =
GetDescriptorTrack(kDefaultDescriptorTrackUuid);
- if (opt_track_id)
- return *opt_track_id;
+ if (track_id)
+ return *track_id;
- return UpdateDescriptorTrack(kDefaultDescriptorTrackUuid,
- default_descriptor_track_name_);
+ // Otherwise reserve a new track and resolve it.
+ ReserveDescriptorChildTrack(kDefaultDescriptorTrackUuid, /*parent_uuid=*/0);
+ track_id = GetDescriptorTrack(kDefaultDescriptorTrackUuid);
+
+ auto* tracks = context_->storage->mutable_track_table();
+ tracks->mutable_name()->Set(*tracks->id().IndexOf(*track_id),
+ default_descriptor_track_name_);
+ return *track_id;
}
TrackId TrackTracker::InternGlobalCounterTrack(StringId name) {
diff --git a/src/trace_processor/track_tracker.h b/src/trace_processor/track_tracker.h
index 3a2b0ba..803b908 100644
--- a/src/trace_processor/track_tracker.h
+++ b/src/trace_processor/track_tracker.h
@@ -31,6 +31,9 @@
// Interns a thread track into the storage.
TrackId InternThreadTrack(UniqueTid utid);
+ // Interns a process track into the storage.
+ TrackId InternProcessTrack(UniquePid upid);
+
// Interns a Fuchsia async track into the storage.
TrackId InternFuchsiaAsyncTrack(StringId name, int64_t correlation_id);
@@ -56,21 +59,50 @@
// Lazily creates the track for legacy Chrome global instant events.
TrackId GetOrCreateLegacyChromeGlobalInstantTrack();
- // Create or update the track for the TrackDescriptor with the given |uuid|.
- // Optionally, associate the track with a process or thread.
- TrackId UpdateDescriptorTrack(uint64_t uuid,
- StringId name,
- base::Optional<UniquePid> upid = base::nullopt,
- base::Optional<UniqueTid> utid = base::nullopt);
+ // Associate a TrackDescriptor track identified by the given |uuid| with a
+ // process's |pid|. This is called during tokenization. If a reservation for
+ // the same |uuid| already exists, verifies that the present reservation
+ // matches the new one.
+ //
+ // The track will be resolved to the process track (see InternProcessTrack())
+ // upon the first call to GetDescriptorTrack() with the same |uuid|. At this
+ // time, |pid| will also be resolved to a |upid|.
+ void ReserveDescriptorProcessTrack(uint64_t uuid,
+ uint32_t pid,
+ int64_t timestamp);
+
+ // Associate a TrackDescriptor track identified by the given |uuid| with a
+ // thread's |pid| and |tid|. This is called during tokenization. If a
+ // reservation for the same |uuid| already exists, verifies that the present
+ // reservation matches the new one.
+ //
+ // The track will be resolved to the thread track (see InternThreadTrack())
+ // upon the first call to GetDescriptorTrack() with the same |uuid|. At this
+ // time, |pid| will also be resolved to a |upid|.
+ void ReserveDescriptorThreadTrack(uint64_t uuid,
+ uint64_t parent_uuid,
+ uint32_t pid,
+ uint32_t tid,
+ int64_t timestamp);
+
+ // Associate a TrackDescriptor track identified by the given |uuid| with a
+ // parent track (usually a process- or thread-associated track). This is
+ // called during tokenization. If a reservation for the same |uuid| already
+ // exists, will attempt to update it.
+ //
+ // The track will be created upon the first call to GetDescriptorTrack() with
+ // the same |uuid|. If |parent_uuid| is 0, the track will become a global
+ // track. Otherwise, it will become a new track of the same type as its parent
+ // track.
+ void ReserveDescriptorChildTrack(uint64_t uuid, uint64_t parent_uuid);
// Returns the ID of the track for the TrackDescriptor with the given |uuid|.
- // Returns nullopt if no TrackDescriptor with this |uuid| has been parsed yet.
- base::Optional<TrackId> GetDescriptorTrack(uint64_t uuid) const;
-
- // Returns the ID of the TrackDescriptor track associated with the given utid.
- // If the trace contained multiple tracks associated with the utid, the first
- // created track is returned. Creates a new track if no such track exists.
- TrackId GetOrCreateDescriptorTrackForThread(UniqueTid utid);
+ // This is called during parsing. The first call to GetDescriptorTrack() for
+ // each |uuid| resolves and inserts the track (and its parent tracks,
+ // following the parent_uuid chain recursively) based on reservations made for
+ // the |uuid|. Returns nullopt if no track for a descriptor with this |uuid|
+ // has been reserved.
+ base::Optional<TrackId> GetDescriptorTrack(uint64_t uuid);
// Returns the ID of the implicit trace-global default TrackDescriptor track.
TrackId GetOrCreateDefaultDescriptorTrack();
@@ -135,18 +167,37 @@
std::tie(r.upid, r.cookie, r.name);
}
};
+ struct DescriptorTrackReservation {
+ uint64_t parent_uuid = 0;
+ base::Optional<uint32_t> pid;
+ base::Optional<uint32_t> tid;
+ int64_t min_timestamp = 0; // only set if |pid| and/or |tid| is set.
+
+ // Whether |other| is a valid descriptor for this track reservation. A track
+ // should always remain nested underneath its original parent.
+ bool IsForSameTrack(const DescriptorTrackReservation& other) {
+ // Note that |timestamp| is ignored for this comparison.
+ return std::tie(parent_uuid, pid, tid) ==
+ std::tie(other.parent_uuid, pid, tid);
+ }
+ };
+
+ TrackId ResolveDescriptorTrack(uint64_t uuid,
+ const DescriptorTrackReservation&);
static constexpr uint64_t kDefaultDescriptorTrackUuid = 0u;
- std::map<UniqueTid /* utid */, TrackId> thread_tracks_;
+ std::map<UniqueTid, TrackId> thread_tracks_;
+ std::map<UniquePid, TrackId> process_tracks_;
std::map<int64_t /* correlation_id */, TrackId> fuchsia_async_tracks_;
std::map<GpuTrackTuple, TrackId> gpu_tracks_;
std::map<ChromeTrackTuple, TrackId> chrome_tracks_;
std::map<AndroidAsyncTrackTuple, TrackId> android_async_tracks_;
std::map<UniquePid, TrackId> chrome_process_instant_tracks_;
base::Optional<TrackId> chrome_global_instant_track_id_;
- std::map<uint64_t /* uuid */, TrackId> descriptor_tracks_;
- std::map<UniqueTid, TrackId> descriptor_tracks_by_utid_;
+ std::map<uint64_t /* uuid */, DescriptorTrackReservation>
+ reserved_descriptor_tracks_;
+ std::map<uint64_t /* uuid */, TrackId> resolved_descriptor_tracks_;
std::map<StringId, TrackId> global_counter_tracks_by_name_;
std::map<std::pair<StringId, uint32_t>, TrackId> cpu_counter_tracks_;
@@ -156,6 +207,11 @@
std::map<std::pair<StringId, int32_t>, TrackId> softirq_counter_tracks_;
std::map<std::pair<StringId, uint32_t>, TrackId> gpu_counter_tracks_;
+ // Stores the descriptor uuid used for the primary process/thread track
+ // for the given upid / utid. Used for pid/tid reuse detection.
+ std::map<UniquePid, uint64_t /*uuid*/> descriptor_uuids_by_upid_;
+ std::map<UniqueTid, uint64_t /*uuid*/> descriptor_uuids_by_utid_;
+
const StringId source_key_ = 0;
const StringId source_id_key_ = 0;
const StringId source_id_is_process_scoped_key_ = 0;