Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Round Robin oracle and eDSL #2177

Merged
merged 45 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fd0d864
add init, push, and pop
Jun 20, 2024
c84e23e
making progress
Jun 21, 2024
102acdc
working progress
Jun 24, 2024
3b42a87
update implementation
Jun 25, 2024
27f6b97
implement RR Queue
Jun 25, 2024
8b97a38
Merge branch 'main' of https://github.com/calyxir/calyx into generali…
Jun 25, 2024
08267f7
tweaked the dump
Jun 25, 2024
8d28373
remove runt stanza, will add back later
Jun 25, 2024
82477a8
Docstring stuff
Jun 25, 2024
3b6cd51
re-upload expect files w/o pretty-printing
Jun 25, 2024
36e2f31
tweak in expect files
Jun 25, 2024
2cd1acf
debug rr_queue.py and add test cases
Jun 26, 2024
6facd8b
move rr_queue files to their own directory
Jun 26, 2024
3e14e77
Merge branch 'main' of https://github.com/calyxir/calyx into generali…
Jun 27, 2024
72172af
tidying up
Jun 27, 2024
b24fffb
delete commented out code
Jun 27, 2024
b722dc5
Whitespace
anshumanmohan Jun 28, 2024
02cd600
Autoformat
anshumanmohan Jun 28, 2024
16caa16
Fix gen_queue script, regen data and expect. Passes runt tests
anshumanmohan Jun 28, 2024
7a98cbd
Bugfix
anshumanmohan Jun 28, 2024
8234be6
Autoformat
anshumanmohan Jun 28, 2024
ad75e07
Tidy eDSL code
anshumanmohan Jun 28, 2024
88ac68f
larger test
Jun 28, 2024
887bd53
add more tests for debugging
Jul 1, 2024
8633672
bug fixes and factoring out code
Jul 1, 2024
871bc93
increase testing
Jul 2, 2024
43a33ae
tweaks
Jul 2, 2024
5a22944
Comments, whitespace, and bring back keepgoing
anshumanmohan Jul 2, 2024
2f4a70e
Some more commentary
anshumanmohan Jul 2, 2024
75f6860
Add failsafe case
anshumanmohan Jul 2, 2024
5ce714f
Factor out more code
anshumanmohan Jul 2, 2024
66e4fc6
Use factored out code bigtime
anshumanmohan Jul 2, 2024
c6c8db0
Bring back numcmds
anshumanmohan Jul 2, 2024
81f002e
A little Python fanciness
anshumanmohan Jul 2, 2024
b9cab55
Turn on well-formedness
anshumanmohan Jul 2, 2024
77c06ec
Rip out stats component
anshumanmohan Jul 2, 2024
c3fbe7e
No need for edge-case logic!
anshumanmohan Jul 2, 2024
7d6c855
Comment
anshumanmohan Jul 2, 2024
a7fcc8e
Simplify peek logic
anshumanmohan Jul 2, 2024
da475f0
TIdy
anshumanmohan Jul 2, 2024
4094f34
Simplify pop logic
anshumanmohan Jul 2, 2024
ab98b8e
Simplify logic using case
anshumanmohan Jul 2, 2024
3b68cc4
Comment
anshumanmohan Jul 2, 2024
a412f04
Merge branch 'main' into generalize_pifo_oracle
anshumanmohan Jul 2, 2024
345ef20
delete strict subdirectory
Jul 2, 2024
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
8 changes: 8 additions & 0 deletions calyx-py/calyx/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,14 @@ def le_store_in_reg(
cell = self.le(width, cellname, signed)
return self.op_store_in_reg(cell, left, right, cell.name, 1, ans_reg)

def ge_store_in_reg(
self, left, right, ans_reg=None, cellname=None, width=None, signed=False
):
"""Inserts wiring into `self` to perform `reg := left >= right`."""
width = width or self.try_infer_width(width, left, right)
cell = self.ge(width, cellname, signed)
return self.op_store_in_reg(cell, left, right, cell.name, 1, ans_reg)

def mult_store_in_reg(
self, left, right, ans_reg=None, cellname=None, width=None, signed=False
):
Expand Down
5 changes: 5 additions & 0 deletions calyx-py/calyx/gen_queue_data_expect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ done
# use binheap_oracle to generate the expected output
python3 queue_data_gen.py $num_cmds --use-rank > ../test/correctness/queues/binheap/stable_binheap.data
cat ../test/correctness/queues/binheap/stable_binheap.data | python3 binheap_oracle.py $num_cmds $queue_size --keepgoing > ../test/correctness/queues/binheap/stable_binheap.expect

# For the Round Robin queues, we drop piezo mode as well and use rrqueue_oracle to
# generate the expected output
python3 queue_data_gen.py 20 > ../test/correctness/queues/rr_queues/rr_queue.data
cat ../test/correctness/queues/rr_queues/rr_queue.data | python3 rrqueue_oracle.py 20 $queue_size --keepgoing > ../test/correctness/queues/rr_queues/rr_queue.expect
99 changes: 95 additions & 4 deletions calyx-py/calyx/queues.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass, field
from typing import Any, List, Optional
from typing import Any, Optional
import heapq


Expand Down Expand Up @@ -152,7 +152,7 @@ def __len__(self) -> int:
@dataclass(order=True)
class RankValue:
priority: int
value: Any=field(compare=False)
value: Any = field(compare=False)


@dataclass
Expand Down Expand Up @@ -192,13 +192,104 @@ def __len__(self) -> int:
return self.len


@dataclass
class RRQueue:
"""
This is a version of a PIFO generalized to `n` flows, with a work conserving
round robin policy. If a flow is silent when it is its turn, that flow
simply skips its turn and the next flow is offered service.

Supports the operations `push`, `pop`, and `peek`.
It takes in a list `boundaries` that must be of length `n`, using which the
client can divide the incoming traffic into `n` flows.
For example, if n = 3 and the client passes boundaries [133, 266, 400],
packets will be divided into three flows: [0, 133], [134, 266], [267, 400].

- At push, we check the `boundaries` list to determine which flow to push to.
Take the boundaries example given earlier, [133, 266, 400].
If we push the value 89, it will end up in flow 0 becuase 89 <= 133,
and 305 would end up in flow 2 since 266 <= 305 <= 400.
- Pop first tries to pop from `hot`. If this succeeds, great. If it fails,
it increments `hot` and therefore continues to check all other flows
in round robin fashion.
- Peek allows the client to see which element is at the head of the queue
without removing it. Thus, peek works in a similar fashion to `pop`, except
`hot` is restored to its original value at the every end.
Further, nothing is actually dequeued.
"""

def __init__(self, n, boundaries, max_len: int):
self.hot = 0
self.n = n
self.pifo_len = 0
self.boundaries = boundaries
self.data = [Fifo(max_len) for _ in range(n)]

self.max_len = max_len
assert (
self.pifo_len <= self.max_len
) # We can't be initialized with a PIFO that is too long.

def push(self, val: int):
"""Pushes `val` to the PIFO."""
if self.pifo_len == self.max_len:
raise QueueError("Cannot push to full PIFO.")
for fifo, boundary in zip(self.data, self.boundaries):
anshumanmohan marked this conversation as resolved.
Show resolved Hide resolved
if val <= boundary:
fifo.push(val)
self.pifo_len += 1
break

def increment_hot(self):
"""Increments `hot`, taking into account wraparound."""
self.hot = 0 if self.hot == (self.n - 1) else self.hot + 1

def pop(self) -> Optional[int]:
"""Pops the PIFO by popping some internal FIFO.
Updates `hot` to be one more than the index of the internal FIFO that
we did pop.
"""
if self.pifo_len == 0:
raise QueueError("Cannot pop from empty PIFO.")

while True:
try:
val = self.data[self.hot].pop()
if val is not None:
self.increment_hot()
self.pifo_len -= 1
return val
self.increment_hot()
except QueueError:
self.increment_hot()
anshumanmohan marked this conversation as resolved.
Show resolved Hide resolved

def peek(self) -> Optional[int]:
"""Peeks into the PIFO. Does not affect what `hot` is."""
if self.pifo_len == 0:
raise QueueError("Cannot peek into empty PIFO.")

original_hot = self.hot
while True:
try:
val = self.data[self.hot].peek()
if val is not None:
self.hot = original_hot
return val
self.increment_hot()
except QueueError:
self.increment_hot()

def __len__(self) -> int:
return self.pifo_len


def operate_queue(queue, max_cmds, commands, values, ranks=None, keepgoing=False):
"""Given the two lists, one of commands and one of values.
Feed these into our queue, and return the answer memory.
"""

ans = []
ranks_or_values = values if ranks == None else ranks
ranks_or_values = values if ranks is None else ranks
for cmd, val, rnk in zip(commands, values, ranks_or_values):
if cmd == 0:
try:
Expand All @@ -218,7 +309,7 @@ def operate_queue(queue, max_cmds, commands, values, ranks=None, keepgoing=False

elif cmd == 2:
try:
if ranks == None:
if ranks is None:
queue.push(val)
else:
queue.push(rnk, val)
Expand Down
18 changes: 18 additions & 0 deletions calyx-py/calyx/rrqueue_oracle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# For usage, see gen_queue_data_expect.sh
import sys
import calyx.queues as queues
from calyx import queue_util

if __name__ == "__main__":
max_cmds, len = int(sys.argv[1]), int(sys.argv[2])
keepgoing = "--keepgoing" in sys.argv
commands, values, _ = queue_util.parse_json()

# Our Round Robin Queue (formerly known as generalized pifo) is simple: it
# just orchestrates n FIFOs, in this case 3. It takes in a list of
# boundaries of length n (in this case 3).
pifo = queues.RRQueue(2, [200, 400], len)

ans = queues.operate_queue(pifo, max_cmds, commands, values, keepgoing=keepgoing)

queue_util.dump_json(ans, commands, values)
89 changes: 89 additions & 0 deletions calyx-py/test/correctness/queues/rr_queues/rr_queue.data
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"commands": {
"data": [
2,
1,
2,
1,
2,
2,
2,
2,
0,
1,
0,
2,
0,
0,
0,
1,
1,
0,
1,
2
],
"format": {
"is_signed": false,
"numeric_type": "bitnum",
"width": 2
}
},
"values": {
"data": [
52,
293,
127,
6,
374,
110,
208,
143,
93,
392,
199,
81,
390,
36,
71,
316,
316,
227,
64,
67
],
"format": {
"is_signed": false,
"numeric_type": "bitnum",
"width": 32
}
},
"ans_mem": {
"data": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"format": {
"is_signed": false,
"numeric_type": "bitnum",
"width": 32
}
}
}
68 changes: 68 additions & 0 deletions calyx-py/test/correctness/queues/rr_queues/rr_queue.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"ans_mem": [
52,
52,
52,
374,
374,
127,
208,
110,
143,
143,
143,
81,
0,
0,
0,
0,
0,
0,
0,
0
],
"commands": [
2,
1,
2,
1,
2,
2,
2,
2,
0,
1,
0,
2,
0,
0,
0,
1,
1,
0,
1,
2
],
"values": [
52,
293,
127,
6,
374,
110,
208,
143,
93,
392,
199,
81,
390,
36,
71,
316,
316,
227,
64,
67
]
}
Loading
Loading