diff --git a/src/trace_redaction/redact_sched_events.cc b/src/trace_redaction/redact_sched_events.cc index c16c2c6980f..f68c1b9f96b 100644 --- a/src/trace_redaction/redact_sched_events.cc +++ b/src/trace_redaction/redact_sched_events.cc @@ -369,9 +369,12 @@ base::Status RedactSchedEvents::OnCompSched( comp_sched.has_switch_next_comm_index(), }; + // The final intern table that will only contain referenced entries. + std::vector dest_intern_table; + if (std::any_of(has_switch_fields.begin(), has_switch_fields.end(), IsTrue)) { - RETURN_IF_ERROR( - OnCompSchedSwitch(context, cpu, comp_sched, &intern_table, message)); + RETURN_IF_ERROR(OnCompSchedSwitch(context, cpu, comp_sched, &intern_table, + &dest_intern_table, message)); } std::array has_waking_fields = { @@ -381,14 +384,14 @@ base::Status RedactSchedEvents::OnCompSched( }; if (std::any_of(has_waking_fields.begin(), has_waking_fields.end(), IsTrue)) { - RETURN_IF_ERROR( - OnCompactSchedWaking(context, comp_sched, &intern_table, message)); + RETURN_IF_ERROR(OnCompactSchedWaking(context, comp_sched, &intern_table, + &dest_intern_table, message)); } // IMPORTANT: The intern table can only be added after switch and waking // because switch and/or waking can/will modify the intern table. - for (auto view : intern_table.values()) { - message->add_intern_table(view.data(), view.size()); + for (const std::string& str : dest_intern_table) { + message->add_intern_table(str.c_str(), str.size()); } return base::OkStatus(); @@ -398,7 +401,8 @@ base::Status RedactSchedEvents::OnCompSchedSwitch( const Context& context, int32_t cpu, protos::pbzero::FtraceEventBundle::CompactSched::Decoder& comp_sched, - InternTable* intern_table, + InternTable* source_intern_table, + std::vector* target_intern_table, protos::pbzero::FtraceEventBundle::CompactSched* message) const { PERFETTO_DCHECK(modifier_); PERFETTO_DCHECK(message); @@ -439,20 +443,23 @@ base::Status RedactSchedEvents::OnCompSchedSwitch( auto pid = *it_pid; auto comm_index = *it_comm; - auto comm = intern_table->Find(comm_index); + auto comm = source_intern_table->Find(comm_index); scratch_str.assign(comm); modifier_->Modify(context, ts, cpu, &pid, &scratch_str); - auto found = intern_table->Push(scratch_str.data(), scratch_str.size()); - - if (found < 0) { - return base::ErrStatus( - "RedactSchedEvents: failed to insert string into intern table."); + // Add the string to the intern table if it is not already there, otherwise, + // reuse it. + auto found = std::find(target_intern_table->begin(), + target_intern_table->end(), scratch_str); + if (found == target_intern_table->end()) { + target_intern_table->push_back(scratch_str); + packed_comm.Append(target_intern_table->size() - 1); + } else { + packed_comm.Append(std::distance(target_intern_table->begin(), found)); } - packed_comm.Append(found); packed_pid.Append(pid); ++it_ts; @@ -516,7 +523,8 @@ base::Status RedactSchedEvents::OnCompSchedSwitch( base::Status RedactSchedEvents::OnCompactSchedWaking( const Context& context, protos::pbzero::FtraceEventBundle::CompactSched::Decoder& compact_sched, - InternTable* intern_table, + InternTable* source_intern_table, + std::vector* target_intern_table, protos::pbzero::FtraceEventBundle::CompactSched* compact_sched_message) const { protozero::PackedVarInt var_comm_index; @@ -552,44 +560,42 @@ base::Status RedactSchedEvents::OnCompactSchedWaking( std::string comm; - std::array parse_errors = {!compact_sched.has_intern_table(), - false, - false, - false, - false, - false, - false}; - + std::array parse_errors = {false, false, false, false, false, false}; // A note on readability, because the waking iterators are the primary focus, // they won't have a "waking" prefix. - auto it_comm_index = compact_sched.waking_comm_index(&parse_errors.at(1)); - auto it_common_flags = compact_sched.waking_common_flags(&parse_errors.at(2)); - auto it_pid = compact_sched.waking_pid(&parse_errors.at(3)); - auto it_prio = compact_sched.waking_prio(&parse_errors.at(4)); - auto it_target_cpu = compact_sched.waking_target_cpu(&parse_errors.at(5)); - auto it_timestamp = compact_sched.waking_timestamp(&parse_errors.at(6)); + auto it_comm_index = compact_sched.waking_comm_index(&parse_errors.at(0)); + auto it_common_flags = compact_sched.waking_common_flags(&parse_errors.at(1)); + auto it_pid = compact_sched.waking_pid(&parse_errors.at(2)); + auto it_prio = compact_sched.waking_prio(&parse_errors.at(3)); + auto it_target_cpu = compact_sched.waking_target_cpu(&parse_errors.at(4)); + auto it_timestamp = compact_sched.waking_timestamp(&parse_errors.at(5)); while (it_comm_index && it_common_flags && it_pid && it_prio && it_target_cpu && it_timestamp) { ts_bucket += *it_timestamp; // add time to the bucket ts_absolute += *it_timestamp; - if (waking_filter_->Includes(context, ts_absolute, *it_pid)) { // Now that the waking event will be kept, it can be modified using the // same rules as switch events. auto pid = *it_pid; - comm.assign(intern_table->Find(*it_comm_index)); + comm.assign(source_intern_table->Find(*it_comm_index)); modifier_->Modify(context, ts_absolute, *it_target_cpu, &pid, &comm); - auto comm_it = intern_table->Push(comm.data(), comm.size()); + auto found = std::find(target_intern_table->begin(), + target_intern_table->end(), comm); + if (found == target_intern_table->end()) { + target_intern_table->push_back(comm); + var_comm_index.Append(target_intern_table->size() - 1); + } else { + var_comm_index.Append( + std::distance(target_intern_table->begin(), found)); + } - var_comm_index.Append(comm_it); var_common_flags.Append(*it_common_flags); var_pid.Append(pid); var_prio.Append(*it_prio); var_target_cpu.Append(*it_target_cpu); var_timestamp.Append(ts_bucket); - ts_bucket = 0; // drain the whole bucket. } diff --git a/src/trace_redaction/redact_sched_events.h b/src/trace_redaction/redact_sched_events.h index f48fea24794..c8888779613 100644 --- a/src/trace_redaction/redact_sched_events.h +++ b/src/trace_redaction/redact_sched_events.h @@ -102,13 +102,15 @@ class RedactSchedEvents : public TransformPrimitive { const Context& context, int32_t cpu, protos::pbzero::FtraceEventBundle::CompactSched::Decoder& comp_sched, - InternTable* intern_table, + InternTable* source_intern_table, + std::vector* target_intern_table, protos::pbzero::FtraceEventBundle::CompactSched* message) const; base::Status OnCompactSchedWaking( const Context& context, protos::pbzero::FtraceEventBundle::CompactSched::Decoder& compact_sched, - InternTable* intern_table, + InternTable* source_intern_table, + std::vector* target_intern_table, protos::pbzero::FtraceEventBundle::CompactSched* compact_sched_message) const; diff --git a/src/trace_redaction/redact_sched_events_unittest.cc b/src/trace_redaction/redact_sched_events_unittest.cc index e3ca9625f96..a24ff010b0b 100644 --- a/src/trace_redaction/redact_sched_events_unittest.cc +++ b/src/trace_redaction/redact_sched_events_unittest.cc @@ -219,6 +219,20 @@ class RedactCompactSchedSwitchTest : public testing::Test { compact_sched->add_switch_next_comm_index(comm); } + void AddWakingEvent(uint64_t ts, + int32_t pid, + int32_t target_cpu, + int32_t prio, + uint32_t comm, + uint32_t common_flags = 0) { + compact_sched->add_waking_timestamp(ts); + compact_sched->add_waking_pid(pid); + compact_sched->add_waking_target_cpu(target_cpu); + compact_sched->add_waking_prio(prio); + compact_sched->add_waking_comm_index(comm); + compact_sched->add_waking_common_flags(common_flags); + } + protos::gen::TracePacket packet_; protos::gen::FtraceEventBundle::CompactSched* compact_sched; @@ -230,10 +244,6 @@ TEST_F(RedactCompactSchedSwitchTest, KeepsTargetCommValues) { uint32_t kCommIndexA = 0; uint32_t kCommIndexB = 1; - // The new entry will be appended to the table. Another primitive can be used - // to reduce the intern string table. - uint32_t kCommIndexNone = 2; - AddSwitchEvent(kTimeA, kPidA, 0, 0, kCommIndexA); AddSwitchEvent(kTimeB, kPidB, 0, 0, kCommIndexB); @@ -251,13 +261,15 @@ TEST_F(RedactCompactSchedSwitchTest, KeepsTargetCommValues) { const auto& compact_sched = bundle.compact_sched(); - // A new entry (empty string) should have been added to the table. - ASSERT_EQ(compact_sched.intern_table_size(), 3); - ASSERT_EQ(compact_sched.intern_table().back(), kCommNone); + // The intern table should contain only referenced entries: kCommA and + // the empty string (replacing kCommB). Unreferenced entries are removed. + ASSERT_EQ(compact_sched.intern_table_size(), 2); + ASSERT_EQ(compact_sched.intern_table().at(0), kCommA); + ASSERT_EQ(compact_sched.intern_table().at(1), kCommNone); ASSERT_EQ(compact_sched.switch_next_comm_index_size(), 2); - ASSERT_EQ(compact_sched.switch_next_comm_index().at(0), kCommIndexA); - ASSERT_EQ(compact_sched.switch_next_comm_index().at(1), kCommIndexNone); + ASSERT_EQ(compact_sched.switch_next_comm_index().at(0), 0u); + ASSERT_EQ(compact_sched.switch_next_comm_index().at(1), 1u); } // If two pids use the same comm, but one pid changes, the shared comm should @@ -282,21 +294,21 @@ TEST_F(RedactCompactSchedSwitchTest, ChangingSharedCommonRetainsComm) { const auto& compact_sched = bundle.compact_sched(); - // A new entry should have been appended, but comm A (previously shared) - // should still exist in the table. - ASSERT_EQ(compact_sched.intern_table_size(), 3); - ASSERT_EQ(compact_sched.intern_table().front(), kCommA); - ASSERT_EQ(compact_sched.intern_table().back(), kCommNone); + // The intern table should contain kCommA and the empty string (replacing + // the comm for PidB). Unreferenced entries are removed. + ASSERT_EQ(compact_sched.intern_table_size(), 2); + ASSERT_EQ(compact_sched.intern_table().at(0), kCommA); + ASSERT_EQ(compact_sched.intern_table().at(1), kCommNone); + + ASSERT_EQ(compact_sched.switch_next_comm_index_size(), 2); + ASSERT_EQ(compact_sched.switch_next_comm_index().at(0), 0u); + ASSERT_EQ(compact_sched.switch_next_comm_index().at(1), 1u); } TEST_F(RedactCompactSchedSwitchTest, RemovesAllCommsIfPackageDoesntExist) { uint32_t kCommIndexA = 0; uint32_t kCommIndexB = 1; - // The new entry will be appended to the table. Another primitive can be used - // to reduce the intern string table. - uint32_t kCommIndexNone = 2; - AddSwitchEvent(kTimeA, kPidA, 0, 0, kCommIndexA); AddSwitchEvent(kTimeB, kPidB, 0, 0, kCommIndexB); @@ -314,13 +326,14 @@ TEST_F(RedactCompactSchedSwitchTest, RemovesAllCommsIfPackageDoesntExist) { const auto& compact_sched = bundle.compact_sched(); - // A new entry (empty string) should have been added to the table. - ASSERT_EQ(compact_sched.intern_table_size(), 3); - ASSERT_EQ(compact_sched.intern_table().back(), kCommNone); + // Because no package matched, all comms are replaced with empty string. + // Unreferenced original comms are dropped, leaving only the empty string. + ASSERT_EQ(compact_sched.intern_table_size(), 1); + ASSERT_EQ(compact_sched.intern_table().at(0), kCommNone); ASSERT_EQ(compact_sched.switch_next_comm_index_size(), 2); - ASSERT_EQ(compact_sched.switch_next_comm_index().at(0), kCommIndexNone); - ASSERT_EQ(compact_sched.switch_next_comm_index().at(1), kCommIndexNone); + ASSERT_EQ(compact_sched.switch_next_comm_index().at(0), 0u); + ASSERT_EQ(compact_sched.switch_next_comm_index().at(1), 0u); } TEST_F(RedactCompactSchedSwitchTest, CanChangePid) { @@ -357,6 +370,294 @@ TEST_F(RedactCompactSchedSwitchTest, CanChangePid) { ASSERT_EQ(compact_sched.switch_next_pid().at(1), kPidC); } +TEST_F(RedactCompactSchedSwitchTest, PrunesUnreferencedInternTableEntries) { + compact_sched->add_intern_table(kCommC); + + // Switch events only reference index 0 (kCommA) and index 2 (kCommC). + // Index 1 (kCommB) is unreferenced. + AddSwitchEvent(kTimeA, kPidA, 0, 0, 0); + AddSwitchEvent(kTimeB, kPidA, 0, 0, 2); + + context_.package_uid = kUidA; + redact_.emplace_modifier(); + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + // The unreferenced entry (kCommB at old index 1) is pruned. + ASSERT_EQ(redacted_sched.intern_table_size(), 2); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommA); + ASSERT_EQ(redacted_sched.intern_table().at(1), kCommC); + + // Indices are remapped: old 0 -> new 0, old 2 -> new 1. + ASSERT_EQ(redacted_sched.switch_next_comm_index_size(), 2); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(1), 1u); +} + +TEST_F(RedactCompactSchedSwitchTest, DeduplicatesRedactedCommEntries) { + // 3 events for non-target PID (kPidB), all using kCommB (index 1). + AddSwitchEvent(kTimeA, kPidB, 0, 0, 1); + AddSwitchEvent(kTimeB, kPidB, 0, 0, 1); + AddSwitchEvent(kTimeB, kPidB, 0, 0, 1); + + context_.package_uid = kUidA; + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + // Only one entry ("") should remain in the intern table after clearing. + ASSERT_EQ(redacted_sched.intern_table_size(), 1); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommNone); + + // All three events point to index 0 (""). + ASSERT_EQ(redacted_sched.switch_next_comm_index_size(), 3); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(1), 0u); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(2), 0u); +} + +TEST_F(RedactCompactSchedSwitchTest, SharesInternTableWithWakingEvents) { + uint32_t kCommIndexA = 0; + uint32_t kCommIndexB = 1; + + AddSwitchEvent(kTimeA, kPidA, 0, 0, kCommIndexA); + AddWakingEvent(kTimeA, kPidB, kCpuA, 0, kCommIndexB); + AddWakingEvent(kTimeB, kPidA, kCpuA, 0, kCommIndexA); + AddSwitchEvent(kTimeB, kPidB, 0, 0, kCommIndexB); + + context_.package_uid = kUidA; + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + // Shared intern table contains only kCommA and "" (kCommNone). + ASSERT_EQ(redacted_sched.intern_table_size(), 2); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommA); + ASSERT_EQ(redacted_sched.intern_table().at(1), kCommNone); + + ASSERT_EQ(redacted_sched.switch_next_comm_index_size(), 2); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.switch_next_comm_index().at(1), 1u); + + ASSERT_EQ(redacted_sched.waking_comm_index_size(), 2); + ASSERT_EQ(redacted_sched.waking_comm_index().at(0), 1u); + ASSERT_EQ(redacted_sched.waking_comm_index().at(1), 0u); +} + +class RedactCompactSchedWakingTest : public testing::Test { + protected: + void SetUp() override { + context_.timeline = std::make_unique(); + context_.timeline->Append( + ProcessThreadTimeline::Event::Open(kTimeA, kPidA, kNoParent, kUidA)); + context_.timeline->Append( + ProcessThreadTimeline::Event::Open(kTimeA, kPidB, kNoParent, kUidB)); + context_.timeline->Sort(); + + auto* bundle = packet_.mutable_ftrace_events(); + bundle->set_cpu(kCpuA); + + compact_sched = bundle->mutable_compact_sched(); + + compact_sched->add_intern_table(kCommA); + compact_sched->add_intern_table(kCommB); + + redact_.emplace_modifier(); + redact_.emplace_waking_filter(); + } + + void AddWakingEvent(uint64_t ts, + int32_t pid, + int32_t target_cpu, + int32_t prio, + uint32_t comm, + uint32_t common_flags = 0) { + compact_sched->add_waking_timestamp(ts); + compact_sched->add_waking_pid(pid); + compact_sched->add_waking_target_cpu(target_cpu); + compact_sched->add_waking_prio(prio); + compact_sched->add_waking_comm_index(comm); + compact_sched->add_waking_common_flags(common_flags); + } + + protos::gen::TracePacket packet_; + protos::gen::FtraceEventBundle::CompactSched* compact_sched; + + Context context_; + RedactSchedEvents redact_; +}; + +TEST_F(RedactCompactSchedWakingTest, KeepsTargetCommValues) { + uint32_t kCommIndexA = 0; + uint32_t kCommIndexB = 1; + + AddWakingEvent(kTimeA, kPidA, kCpuA, 0, kCommIndexA); + AddWakingEvent(kTimeB, kPidB, kCpuA, 0, kCommIndexB); + + context_.package_uid = kUidA; + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + ASSERT_EQ(redacted_sched.intern_table_size(), 2); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommA); + ASSERT_EQ(redacted_sched.intern_table().at(1), kCommNone); + + ASSERT_EQ(redacted_sched.waking_comm_index_size(), 2); + ASSERT_EQ(redacted_sched.waking_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.waking_comm_index().at(1), 1u); +} + +TEST_F(RedactCompactSchedWakingTest, RemovesAllCommsIfPackageDoesntExist) { + uint32_t kCommIndexA = 0; + uint32_t kCommIndexB = 1; + + AddWakingEvent(kTimeA, kPidA, kCpuA, 0, kCommIndexA); + AddWakingEvent(kTimeB, kPidB, kCpuA, 0, kCommIndexB); + + context_.package_uid = kUidC; + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + ASSERT_EQ(redacted_sched.intern_table_size(), 1); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommNone); + + ASSERT_EQ(redacted_sched.waking_comm_index_size(), 2); + ASSERT_EQ(redacted_sched.waking_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.waking_comm_index().at(1), 0u); +} + +TEST_F(RedactCompactSchedWakingTest, PrunesUnreferencedInternTableEntries) { + compact_sched->add_intern_table(kCommC); + + // Only reference index 0 (kCommA) and index 2 (kCommC). + // Index 1 (kCommB) is unreferenced. + AddWakingEvent(kTimeA, kPidA, kCpuA, 0, 0); + AddWakingEvent(kTimeB, kPidA, kCpuA, 0, 2); + + context_.package_uid = kUidA; + redact_.emplace_modifier(); + redact_.emplace_waking_filter(); + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + ASSERT_EQ(redacted_sched.intern_table_size(), 2); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommA); + ASSERT_EQ(redacted_sched.intern_table().at(1), kCommC); + + ASSERT_EQ(redacted_sched.waking_comm_index_size(), 2); + ASSERT_EQ(redacted_sched.waking_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.waking_comm_index().at(1), 1u); +} + +TEST_F(RedactCompactSchedWakingTest, DeduplicatesRedactedCommEntries) { + AddWakingEvent(kTimeA, kPidB, kCpuA, 0, 1); + AddWakingEvent(kTimeB, kPidB, kCpuA, 0, 1); + AddWakingEvent(kTimeB, kPidB, kCpuA, 0, 1); + + context_.package_uid = kUidA; + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + ASSERT_EQ(redacted_sched.intern_table_size(), 1); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommNone); + + ASSERT_EQ(redacted_sched.waking_comm_index_size(), 3); + ASSERT_EQ(redacted_sched.waking_comm_index().at(0), 0u); + ASSERT_EQ(redacted_sched.waking_comm_index().at(1), 0u); + ASSERT_EQ(redacted_sched.waking_comm_index().at(2), 0u); +} + +TEST_F(RedactCompactSchedWakingTest, DropsFilteredWakingEventsAndTheirComms) { + // Use ConnectedToPackage filter so waking event for PidB is filtered out. + redact_.emplace_waking_filter(); + + AddWakingEvent(kTimeA, kPidA, kCpuA, 0, 0); + AddWakingEvent(kTimeB, kPidB, kCpuA, 0, 1); + + context_.package_uid = kUidA; + + auto packet_buffer = packet_.SerializeAsString(); + ASSERT_OK(redact_.Transform(context_, &packet_buffer)); + + protos::gen::TracePacket packet; + ASSERT_TRUE(packet.ParseFromString(packet_buffer)); + + const auto& bundle = packet.ftrace_events(); + ASSERT_TRUE(bundle.has_compact_sched()); + + const auto& redacted_sched = bundle.compact_sched(); + + // Only kCommA (for kPidA) should be in the intern table. kCommB is never + // referenced. + ASSERT_EQ(redacted_sched.intern_table_size(), 1); + ASSERT_EQ(redacted_sched.intern_table().at(0), kCommA); + + // Only one waking event (for PidA) should remain. + ASSERT_EQ(redacted_sched.waking_comm_index_size(), 1); + ASSERT_EQ(redacted_sched.waking_comm_index().at(0), 0u); +} + class RedactSchedWakingFtraceEventTest : public testing::Test { protected: void SetUp() override {