Skip to content

Commit f8e9d72

Browse files
Deque, deduplicate yields, propagate thread_id
1 parent 7315953 commit f8e9d72

1 file changed

Lines changed: 24 additions & 8 deletions

File tree

Lib/profiling/sampling/collector.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from abc import ABC, abstractmethod
2+
from collections import deque
23

34
from _remote_debugging import FrameInfo
45

@@ -71,11 +72,15 @@ def _find_leaf_tasks(self, child_to_parents, all_task_ids):
7172

7273
def _build_linear_stacks(self, leaf_task_ids, task_map, child_to_parents):
7374
for leaf_id in leaf_task_ids:
74-
# BFS queue: (current_task_id, frames_so_far, path_for_cycle_detection)
75-
queue = [(leaf_id, [], frozenset())]
75+
# Track yielded paths to avoid duplicates from multiple parent paths
76+
yielded_paths = set()
77+
78+
# BFS queue: (current_task_id, frames_so_far, path_for_cycle_detection, thread_id)
79+
# Use deque for O(1) popleft instead of O(n) list.pop(0)
80+
queue = deque([(leaf_id, [], frozenset(), None)])
7681

7782
while queue:
78-
current_id, frames, path = queue.pop(0)
83+
current_id, frames, path, thread_id = queue.popleft()
7984

8085
# Cycle detection
8186
if current_id in path:
@@ -84,12 +89,20 @@ def _build_linear_stacks(self, leaf_task_ids, task_map, child_to_parents):
8489
# End of path (parent ID not in task_map)
8590
if current_id not in task_map:
8691
if frames:
87-
_, thread_id = task_map[leaf_id]
88-
yield frames, thread_id, leaf_id
92+
# Deduplicate yields based on path taken
93+
path_sig = frozenset(path)
94+
if path_sig not in yielded_paths:
95+
yielded_paths.add(path_sig)
96+
yield frames, thread_id, leaf_id
8997
continue
9098

9199
# Process current task
92100
task_info, tid = task_map[current_id]
101+
102+
# Set thread_id from first task if not already set
103+
if thread_id is None:
104+
thread_id = tid
105+
93106
new_frames = list(frames)
94107
new_path = path | {current_id}
95108

@@ -107,9 +120,12 @@ def _build_linear_stacks(self, leaf_task_ids, task_map, child_to_parents):
107120
parent_ids = child_to_parents.get(current_id, [])
108121

109122
if not parent_ids:
110-
# Root task - yield complete stack
111-
yield new_frames, tid, leaf_id
123+
# Root task - yield complete stack (deduplicate)
124+
path_sig = frozenset(new_path)
125+
if path_sig not in yielded_paths:
126+
yielded_paths.add(path_sig)
127+
yield new_frames, thread_id, leaf_id
112128
else:
113129
# Continue to each parent (creates multiple paths if >1 parent)
114130
for parent_id in parent_ids:
115-
queue.append((parent_id, new_frames, new_path))
131+
queue.append((parent_id, new_frames, new_path, thread_id))

0 commit comments

Comments
 (0)