computeSpans function

List<TraceSpan> computeSpans(
  1. List<TraceEvent> events
)

Reconstructs TraceSpans from raw TraceEvents.

Implementation

List<TraceSpan> computeSpans(List<TraceEvent> events) {
  final sorted = List<TraceEvent>.from(events)
    ..sort((a, b) => a.timestamp.compareTo(b.timestamp));

  final absoluteMaxTimestamp = sorted.isEmpty ? 0 : sorted.last.timestamp;

  final List<TraceSpan> spans = [];
  final Map<int, List<_StackEntry>> activeStacksByTid = {};

  for (final event in sorted) {
    final tid = event.tid;
    activeStacksByTid.putIfAbsent(tid, () => []);
    final stack = activeStacksByTid[tid]!;

    if (event.phase == 'B') {
      stack.add(_StackEntry(event, stack.length));
    } else if (event.phase == 'E') {
      int matchIdx = -1;
      for (int i = stack.length - 1; i >= 0; i--) {
        if (stack[i].event.name == event.name) {
          matchIdx = i;
          break;
        }
      }
      if (matchIdx != -1) {
        // Pop orphaned children above the matched parent
        while (stack.length > matchIdx + 1) {
          final orphanEntry = stack.removeLast();
          final orphanEvent = orphanEntry.event;
          spans.add(
            TraceSpan(
              name: orphanEvent.name,
              category: orphanEvent.category,
              startUs: orphanEvent.timestamp,
              endUs: event.timestamp, // Auto-closed at parent's end
              depth: orphanEntry.depth,
              args: orphanEvent.args,
            ),
          );
        }

        // Pop the actual matched parent
        final beginEntry = stack.removeLast();
        final begin = beginEntry.event;
        spans.add(
          TraceSpan(
            name: begin.name,
            category: begin.category,
            startUs: begin.timestamp,
            endUs: event.timestamp,
            depth: beginEntry.depth,
            args: begin.args,
          ),
        );
      }
    } else if (event.phase == 'i') {
      spans.add(
        TraceSpan(
          name: event.name,
          category: event.category,
          startUs: event.timestamp,
          endUs: event.timestamp + 1,
          depth: stack.length,
          args: event.args,
        ),
      );
    }
  }
  for (final tid in activeStacksByTid.keys) {
    for (final entry in activeStacksByTid[tid]!) {
      final begin = entry.event;
      spans.add(
        TraceSpan(
          name: begin.name,
          category: begin.category,
          startUs: begin.timestamp,
          endUs:
              absoluteMaxTimestamp, // Indicates missing 'E' phase is clamped to trace end
          depth: entry.depth,
          args: begin.args,
        ),
      );
    }
  }
  return spans;
}