@@ -38,18 +38,24 @@ def _iter_all_frames(self, stack_frames, skip_idle=False):
3838 def _iter_async_frames (self , awaited_info_list ):
3939 """
4040 Iterate over all async frame stacks from awaited info.
41- Yields one stack per task in LEAF→ROOT order: [task body, task marker, parent body, ..., Program Root]
4241 """
43- # Index all tasks by ID
42+ # First, index all tasks by their IDs so we can look up parents easily
4443 all_tasks = {}
4544 for awaited_info in awaited_info_list :
4645 for task_info in awaited_info .awaited_by :
4746 all_tasks [task_info .task_id ] = (task_info , awaited_info .thread_id )
4847
49- cache = {} # Memoize parent chains
48+ # Use a cache for memoizing parent chains so we don't recompute them repeatedly
49+ cache = {}
5050
5151 def build_parent_chain (task_id , parent_id ):
52- """Build ancestor chain: [await-site frames, grandparent chain..., Program Root]"""
52+ """
53+ Recursively build the parent chain for a given task by:
54+ - Finding the parent's await-site frames
55+ - Recursing up the parent chain until reaching Program Root
56+ - Add Program Root at the top of the chain
57+ - Cache results along the way to avoid redundant work
58+ """
5359 if parent_id in cache :
5460 return cache [parent_id ]
5561
@@ -72,36 +78,36 @@ def build_parent_chain(task_id, parent_id):
7278 chain = await_frames + build_parent_chain (parent_id , grandparent_id )
7379 else :
7480 # Parent is root or grandparent not tracked
75- root_frame = FrameInfo (("<thread >" , 0 , "Program Root " ))
81+ root_frame = FrameInfo (("<root >" , 0 , "<all tasks> " ))
7682 chain = await_frames + [root_frame ]
7783
7884 cache [parent_id ] = chain
7985 return chain
8086
81- # Yield one stack per task (including parents doing their own work)
82- for task_id , (task_info , thread_id ) in all_tasks .items ():
83- # Collect task's coroutine frames
87+ # Yield one complete stack per task in LEAF→ROOT order
88+ for task_id , (task_info , _ ) in all_tasks .items ():
89+ # Start with the task's own body frames (deepest frames first)
8490 body_frames = [
8591 frame
8692 for coro in (task_info .coroutine_stack or [])
8793 for frame in (coro .call_stack or [])
8894 ]
8995
90- # Build complete stack with parent chain
9196 if task_info .awaited_by and task_info .awaited_by [0 ].task_name :
92- # Child task: add synthetic marker to distinguish from parent
97+ # Add synthetic frame for the task itself
9398 task_name = task_info .task_name or f"Task-{ task_id } "
9499 synthetic = FrameInfo (("<task>" , 0 , f"running { task_name } " ))
95100
101+ # Append parent chain (await-site frames + parents recursively)
96102 parent_id = task_info .awaited_by [0 ].task_name
97103 if parent_id in all_tasks :
98104 parent_chain = build_parent_chain (task_id , parent_id )
99- yield body_frames + [synthetic ] + parent_chain , thread_id , 0
105+ yield body_frames + [synthetic ] + parent_chain , task_id
100106 else :
101- # Parent not tracked, treat as root task
102- root = FrameInfo (("<thread >" , 0 , "Program Root " ))
103- yield body_frames + [synthetic , root ], thread_id , 0
107+ # No tracked parent, just add root marker
108+ root = FrameInfo (("<root >" , 0 , "<all tasks> " ))
109+ yield body_frames + [synthetic , root ], task_id
104110 else :
105- # Root task: no synthetic marker needed, just add Program Root
106- root = FrameInfo (("<thread >" , 0 , "Program Root " ))
107- yield body_frames + [root ], thread_id , 0
111+ # Root task: no synthetic marker needed, just add root marker
112+ root = FrameInfo (("<root >" , 0 , "<all tasks> " ))
113+ yield body_frames + [root ], task_id
0 commit comments