Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
af65c15
It might work but the code is bad
savannahostrowski Nov 3, 2025
ec28f88
Account for function doing CPU work before/after spawning workers
savannahostrowski Nov 3, 2025
1e01766
Merge branch 'main' into async-tachyon
savannahostrowski Nov 3, 2025
2a2e197
Code cleanup
savannahostrowski Nov 3, 2025
61dc0bb
WIP
savannahostrowski Nov 3, 2025
c9c34a5
Merge branch 'main' into async-tachyon
savannahostrowski Nov 13, 2025
cc9e9ab
Remove depth
savannahostrowski Nov 13, 2025
9b22f1e
Make keyword only
savannahostrowski Nov 13, 2025
890474d
Fix tests
savannahostrowski Nov 13, 2025
563ecff
Bruuuh, it worked
savannahostrowski Nov 13, 2025
112ce73
Simplify algo
pablogsal Nov 14, 2025
2beed97
Fix multiple parents
pablogsal Nov 14, 2025
7315953
Good shit
pablogsal Nov 14, 2025
f8e9d72
Deque, deduplicate yields, propagate thread_id
savannahostrowski Nov 14, 2025
9a4875f
📜🤖 Added by blurb_it.
blurb-it[bot] Nov 14, 2025
ec6fb51
Remove deduplication of leaves to ensure call stacks can be properly …
savannahostrowski Nov 14, 2025
67e1f74
Merge branch 'async-tachyon' of https://github.com/savannahostrowski/…
savannahostrowski Nov 14, 2025
e9ae950
Fix WASI
savannahostrowski Nov 14, 2025
acef9a0
More WASI fixes
savannahostrowski Nov 14, 2025
2953454
Merge main
savannahostrowski Nov 23, 2025
09f5205
Fix tests
savannahostrowski Nov 23, 2025
dc7abae
Fix broken imports
savannahostrowski Nov 24, 2025
36c8b3c
Remove old test file
savannahostrowski Nov 24, 2025
be6d228
Merge remote-tracking branch 'upstream/main' into async-tachyon
pablogsal Nov 24, 2025
64ccb1a
Fixes
pablogsal Nov 24, 2025
fca9c88
fixup! Fixes
pablogsal Nov 25, 2025
394069d
Merge main
savannahostrowski Dec 1, 2025
3d9d2fb
Fix test error
savannahostrowski Dec 1, 2025
1134431
Fix quotations for consistency
savannahostrowski Dec 1, 2025
f0242e1
Merge remote-tracking branch 'upstream/main' into async-tachyon
pablogsal Dec 6, 2025
56661dc
Update to latest main
pablogsal Dec 6, 2025
ff983d8
Fix tests
pablogsal Dec 6, 2025
2203021
Fix tests
pablogsal Dec 6, 2025
e6eaa2c
CLI update
pablogsal Dec 6, 2025
47ebc11
Small fixes
pablogsal Dec 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix multiple parents
  • Loading branch information
pablogsal committed Nov 14, 2025
commit 2beed97a86bca98e6c531ae0a790cc19095e2a0c
73 changes: 55 additions & 18 deletions Lib/profiling/sampling/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def _iter_async_frames(self, awaited_info_list):
"""Iterate over linear stacks for all leaf tasks (hot path optimized)."""
# Build adjacency graph (O(n))
task_map = {}
child_to_parent = {}
child_to_parents = {}
all_task_ids = set()

for awaited_info in awaited_info_list:
Expand All @@ -49,32 +49,69 @@ def _iter_async_frames(self, awaited_info_list):
task_map[task_id] = (task_info, thread_id)
all_task_ids.add(task_id)
if task_info.awaited_by:
child_to_parent[task_id] = task_info.awaited_by[0].task_name
# Store all parent coroutines, not just [0]
child_to_parents[task_id] = task_info.awaited_by

# Identify leaf tasks (O(n))
leaf_task_ids = all_task_ids - set(child_to_parent.values())

# Build linear stacks for each leaf (O(n × depth))
# Collect all parent task IDs from all coroutines
all_parent_ids = set()
for parent_coros in child_to_parents.values():
for parent_coro in parent_coros:
all_parent_ids.add(parent_coro.task_name)
leaf_task_ids = all_task_ids - all_parent_ids

# Build linear stacks for each leaf (O(n × depth × num_paths))
# For tasks with multiple parents, we generate one stack per parent path
for leaf_id in leaf_task_ids:
frames = []
current_id = leaf_id
thread_id = None
# Use BFS to explore all paths from leaf to root
# Queue items: (current_task_id, frames_accumulated)
queue = [(leaf_id, [])]
visited = set()

while queue:
current_id, frames = queue.pop(0)

# Avoid processing the same task twice in this path
if current_id in visited:
continue
visited.add(current_id)

if current_id not in task_map:
# Reached end of path - yield if we have frames
if frames:
_, thread_id = task_map[leaf_id]
yield frames, thread_id, leaf_id
continue

while current_id in task_map:
task_info, tid = task_map[current_id]
if thread_id is None:
thread_id = tid

# Add frames from coroutine stack
# Add this task's frames
new_frames = list(frames)
if task_info.coroutine_stack:
for frame in task_info.coroutine_stack[0].call_stack:
frames.append(frame)
new_frames.append(frame)

# Add task marker
# Add task boundary marker
task_name = task_info.task_name or "Task-" + str(task_info.task_id)
frames.append(FrameInfo(("<task>", 0, task_name)))
new_frames.append(FrameInfo(("<task>", 0, task_name)))

# Get parent coroutines
parent_coros = child_to_parents.get(current_id)
if not parent_coros:
# No parents - this is the root, yield the complete stack
yield new_frames, tid, leaf_id
continue

# For each parent coroutine, add its await frames and continue to parent task
for parent_coro in parent_coros:
parent_task_id = parent_coro.task_name

# Move to parent
current_id = child_to_parent.get(current_id)
# Add the parent's await-site frames (where parent awaits this task)
path_frames = list(new_frames)
for frame in parent_coro.call_stack:
path_frames.append(frame)

yield frames, thread_id, leaf_id
# Continue BFS with parent task
# Note: parent_coro.call_stack contains the frames from the parent task,
# so we should NOT add parent task's coroutine_stack again
queue.append((parent_task_id, path_frames))
Loading