Support update name
diff --git a/src/trace_processor/importers/common/slice_tracker.cc b/src/trace_processor/importers/common/slice_tracker.cc index f8608f2..4991e87 100644 --- a/src/trace_processor/importers/common/slice_tracker.cc +++ b/src/trace_processor/importers/common/slice_tracker.cc
@@ -246,29 +246,54 @@ if (!MaybeCloseStack(timestamp, kPendingDuration, stack, track_id)) { return std::nullopt; } + if (stack.empty()) { - return std::nullopt; - } - - auto* slices = context_->storage->mutable_slice_table(); - std::optional<uint32_t> stack_idx = finder(stack); - - if (!stack_idx) { return StartSlice(timestamp, kPendingDuration, track_id, args_callback, std::move(inserter)); } - const auto& slice_info = stack[stack_idx.value()]; + auto* slices = context_->storage->mutable_slice_table(); - tables::SliceTable::RowReference ref = slice_info.row.ToRowReference(slices); - PERFETTO_DCHECK(ref.dur() == kPendingDuration); - - ArgsTracker& tracker = stack[stack_idx.value()].args_tracker; - if (args_callback) { - auto bound_inserter = tracker.AddArgsTo(ref.id()); - args_callback(&bound_inserter); + std::optional<uint32_t> top_incomplete_idx; + for (int i = static_cast<int>(stack.size()) - 1; i >= 0; i--) { + auto ref = stack[static_cast<size_t>(i)].row.ToRowReference(slices); + if (ref.dur() == kPendingDuration) { + top_incomplete_idx = static_cast<uint32_t>(i); + break; + } } - return ref.id(); + + if (top_incomplete_idx) { + const auto& slice_info = stack[*top_incomplete_idx]; + auto ref = slice_info.row.ToRowReference(slices); + + std::optional<uint32_t> matching_idx = finder(stack); + + if (matching_idx && *matching_idx == *top_incomplete_idx) { + // It matches and it is the top-most incomplete slice. Update it. + ArgsTracker& tracker = stack[*top_incomplete_idx].args_tracker; + if (args_callback) { + auto bound_inserter = tracker.AddArgsTo(ref.id()); + args_callback(&bound_inserter); + } + return ref.id(); + } else { + // It does not match the top-most incomplete slice. + // End the top-most incomplete slice. + ref.set_dur(timestamp - ref.ts()); + + if (*top_incomplete_idx == stack.size() - 1) { + StackPop(track_id); + } + + return StartSlice(timestamp, kPendingDuration, track_id, args_callback, + std::move(inserter)); + } + } else { + // No incomplete slice on stack. + return StartSlice(timestamp, kPendingDuration, track_id, args_callback, + std::move(inserter)); + } } std::optional<SliceId> SliceTracker::CompleteSlice(
diff --git a/src/trace_processor/importers/common/slice_tracker_unittest.cc b/src/trace_processor/importers/common/slice_tracker_unittest.cc index 538c610..4b3748f 100644 --- a/src/trace_processor/importers/common/slice_tracker_unittest.cc +++ b/src/trace_processor/importers/common/slice_tracker_unittest.cc
@@ -223,6 +223,32 @@ EXPECT_EQ(ar0.int_value(), 10); } +TEST_F(SliceTrackerTest, UpdateNameMismatch) { + SliceTracker tracker(&context_); + + constexpr TrackId track{22u}; + tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/, + StringId::Raw(1) /*name*/); + tracker.Update(5 /*ts*/, track, kNullStringId /*cat*/, + StringId::Raw(2) /*name*/); // Different name + tracker.End(10 /*ts*/, track); + + const auto& slices = context_.storage->slice_table(); + EXPECT_EQ(slices.row_count(), 2u); + + // First slice should be closed at ts=5 + auto sr0 = slices[0]; + EXPECT_EQ(sr0.ts(), 2); + EXPECT_EQ(sr0.dur(), 3); // 5 - 2 + EXPECT_EQ(sr0.name().value_or(kNullStringId).raw_id(), 1u); + + // Second slice should start at ts=5 and be closed at ts=10 + auto sr1 = slices[1]; + EXPECT_EQ(sr1.ts(), 5); + EXPECT_EQ(sr1.dur(), 5); // 10 - 5 + EXPECT_EQ(sr1.name().value_or(kNullStringId).raw_id(), 2u); +} + TEST_F(SliceTrackerTest, OneSliceWithArgsWithTranslatedName) { SliceTracker tracker(&context_);