Skip to content

Commit 0cc0258

Browse files
cduckRoger-luo
authored andcommitted
Make WorkList actually O(1), not secretly O(n) (#534)
The docstring was a lie. > The worklist is a stack that allows for O(1) removal of elements from the stack. When running bloqade-circuit and other passes my large kernels, this PR speeds up my program by 60% from 1120s (659s of `WorkList.pop()`) to 453s (11s of `WorkList.pop()`)! DM me for the full profile results. Tests run on kirin v0.17.28. Please backport to 0.17.
1 parent aed1c4e commit 0cc0258

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

src/kirin/worklist.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
from __future__ import annotations
22

3+
from queue import SimpleQueue
34
from typing import Generic, TypeVar, Iterable
4-
from dataclasses import field, dataclass
55

66
ElemType = TypeVar("ElemType")
77

88

9-
@dataclass
10-
class WorkList(Generic[ElemType]):
9+
class WorkList(SimpleQueue, Generic[ElemType]):
1110
"""The worklist data structure.
1211
1312
The worklist is a stack that allows for O(1) removal of elements from the stack.
1413
"""
1514

16-
_stack: list[ElemType] = field(default_factory=list, init=False)
15+
def __len__(self) -> int:
16+
return self.qsize()
17+
18+
def __bool__(self) -> bool:
19+
return not self.empty()
1720

1821
def is_empty(self) -> bool:
19-
return len(self._stack) == 0
22+
return self.empty()
2023

2124
def append(self, item: ElemType) -> None:
22-
self._stack.append(item)
25+
self.put_nowait(item)
2326

2427
def extend(self, items: Iterable[ElemType]) -> None:
25-
self._stack.extend(items)
28+
for item in items:
29+
self.put_nowait(item)
2630

2731
def pop(self) -> ElemType | None:
28-
if self._stack:
29-
return self._stack.pop(0)
30-
return None
32+
if self.empty():
33+
return None
34+
return self.get_nowait()
35+
36+
37+
# Remove one function call from critical speed bottleneck
38+
WorkList.is_empty = WorkList.empty
39+
WorkList.append = WorkList.put_nowait

test/test_worklist.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from kirin.worklist import WorkList
2+
3+
4+
def test_worklist():
5+
wl = WorkList()
6+
7+
assert wl.is_empty()
8+
assert not wl
9+
assert len(wl) == 0
10+
11+
assert wl.pop() is None
12+
13+
assert wl.is_empty()
14+
assert not wl
15+
assert len(wl) == 0
16+
17+
wl.append("A")
18+
19+
assert not wl.is_empty()
20+
assert wl
21+
assert len(wl) == 1
22+
23+
assert wl.pop() == "A"
24+
25+
assert wl.is_empty()
26+
assert not wl
27+
assert len(wl) == 0
28+
29+
wl.append("Z")
30+
wl.extend("BCGFEDCB")
31+
32+
assert not wl.is_empty()
33+
assert wl
34+
assert len(wl) == 9
35+
36+
assert wl.pop() == "Z"
37+
assert wl.pop() == "B"
38+
39+
assert not wl.is_empty()
40+
assert wl
41+
assert len(wl) == 7
42+
43+
rest = []
44+
while wl:
45+
rest.append(wl.pop())
46+
assert rest == list("CGFEDCB")
47+
48+
assert wl.is_empty()
49+
assert not wl
50+
assert len(wl) == 0

0 commit comments

Comments
 (0)