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

Queues: PCAP-based benchmarking harness #2358

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
06bda6b
Add pcap parsing script
polybeandip Oct 15, 2024
0213aff
Refactor queue_call
polybeandip Oct 26, 2024
39a8138
C -> c
polybeandip Oct 27, 2024
61ec5da
Make flow inference a separate component
polybeandip Oct 27, 2024
a41a15d
Remove generate from binheap strict and RR
polybeandip Oct 28, 2024
20352f9
Add strict test for 7 flows
polybeandip Oct 28, 2024
5141884
Fix imports in binheap tests
polybeandip Oct 28, 2024
126bb2d
Rename RR and Strict oracles
polybeandip Oct 28, 2024
0ebd533
Rename binheap (un)tuplify components
polybeandip Oct 28, 2024
789dfcc
Sketch sim_pcap.py
polybeandip Oct 28, 2024
7a66029
More sketching sim_pcap.py and flow_inference.py
polybeandip Oct 30, 2024
31fa876
Move evaluation scripts to separate directory
polybeandip Nov 4, 2024
2dd295f
Pass open files instead of names
polybeandip Nov 4, 2024
614b028
Various tweaks
polybeandip Nov 11, 2024
4b84482
Add --start and --end options to parse_pcap.py
polybeandip Nov 11, 2024
b3c8941
Add CalyxPy state to fud2
polybeandip Nov 11, 2024
33a93d7
Fix fud2 tests
polybeandip Nov 12, 2024
90a59af
Add pkts/bits per sec stats to parse_pcap.py
polybeandip Nov 12, 2024
f330085
Add more PCAP sim logic for binheap rr and strict
polybeandip Nov 12, 2024
5b7ad8b
Factor out flow_inference for strict_or_rr.py
polybeandip Nov 19, 2024
80b0ef4
Comment parse_pcap.py
polybeandip Nov 20, 2024
d2e4aa5
Typo
polybeandip Dec 11, 2024
2600465
Merge branch 'main' into realistic-benchmarking-harness
polybeandip Dec 13, 2024
cf8fd9c
Merge remote-tracking branch 'refs/remotes/origin/realistic-benchmark…
polybeandip Dec 13, 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
Prev Previous commit
Next Next commit
Factor out flow_inference for strict_or_rr.py
polybeandip committed Nov 19, 2024
commit 5b7ad8bcf05fbec612c8571046f0627a6181e7f6
118 changes: 35 additions & 83 deletions frontends/queues/queues/strict_or_rr.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# pylint: disable=import-error
import calyx.builder as cb
import calyx.py_ast as ast
from calyx.utils import bits_needed
import queues.fifo as fifo
import queues.flow_inference as fi

# This determines the maximum possible length of the queue:
# The max length of the queue will be 2^QUEUE_LEN_FACTOR.
@@ -27,22 +29,23 @@ def invoke_subqueue(queue_cell, cmd, value, ans, err) -> cb.invoke:
def insert_queue(
prog,
name,
is_round_robin,
subqueues,
boundaries,
numflows,
order,
round_robin,
flow_infer,
order=None,
queue_len_factor=QUEUE_LEN_FACTOR,
):
"""
Inserts the component `pifo` into the program. If round_robin is true, it
inserts a round robin queue, otherwise it inserts a strict queue. `numflows`
is the number of flows, which must be an integer greater than 0. Boundaries
must be of length `numflows` + 1, where the first boundary is the smallest
number a value can take (eg. 0). `order` is used for strict queues to determine
the order of priority of the subqueues. `order` must be a list of length
`numflows`.
Inserts the component `pifo` into the program, operating over n flows (where n is `len(subqueues)`).
If `is_round_robin` is true, it inserts a round robin queue, otherwise it inserts a strict queue.
`flow_infer` is the component used for flow inference; it must be invoked with an input `value`
and reference register `flow` of size floor(log_2(n)).
`order` is used for strict queues to determine the priority of the subqueues.
`order` must be a permutation of {0, ..., n - 1}.
"""
numflows = len(subqueues)

assert is_round_robin or sorted(order) == list(range(numflows))

pifo: cb.ComponentBuilder = prog.component(name)
cmd = pifo.input("cmd", 1) # the size in bits is 1
@@ -53,6 +56,10 @@ def insert_queue(
pifo.cell(f"queue_{i}", queue_i) for i, queue_i in enumerate(subqueues)
]

flow = pifo.reg(bits_needed(numflows - 1), "flow")
flow_infer = pifo.cell("flow_infer", flow_infer)
infer_flow = cb.invoke(flow_infer, in_value=value, ref_flow=flow)

# If the user wants to pop, we will write the popped value to `ans`.
ans = pifo.reg(32, "ans", is_ref=True)
# We'll raise this as a general error flag for overflow and underflow.
@@ -88,45 +95,21 @@ def insert_queue(
)

# We create a list of invoke-statement handles.
# Each invoke is guarded by a pair of inequality checks on the value register,
# and each pair of guards is unique to the subqueue it is associated with.
# Each invoke is uniquely guarded by an equality check on the flow register.
# This means we can eventually execute all of these invokes in parallel.
invoke_subqueues_value_guard_seq = [
cb.if_with(
pifo.le_use(value, boundaries[b + 1]), # value <= boundaries[b+1]
(
invoke_subqueue(subqueue_cells[b], cmd, value, ans, err)
# In the special case when b = 0,
# we don't need to check the lower bound and we can just `invoke`.
if b == 0 and round_robin
else (
invoke_subqueue(
subqueue_cells[order.index(b)], cmd, value, ans, err
)
if b == 0 and not round_robin
else (
cb.if_with(
pifo.gt_use(value, boundaries[b]), # value > boundaries[b]
invoke_subqueue(
subqueue_cells[order.index(b)], cmd, value, ans, err
),
)
if not round_robin
# Otherwise, we need to check the lower bound and `invoke`
# only if the value is in the interval.
else cb.if_with(
pifo.gt_use(value, boundaries[b]), # value > boundaries[b]
invoke_subqueue(subqueue_cells[b], cmd, value, ans, err),
)
)
invoke_subqueues_flow_guard = pifo.case(
flow.out,
{
n: (
invoke_subqueue(subqueue_cells[n], cmd, value, ans, err)
if is_round_robin
else invoke_subqueue(
subqueue_cells[order.index(n)], cmd, value, ans, err
)
),
)
for b in range(numflows)
]
invoke_subqueues_value_guard = cb.par(
*invoke_subqueues_value_guard_seq
) # Execute in parallel.
)
for n in range(numflows)
},
)

incr_hot_wraparound = cb.if_with(
# If hot = numflows - 1, we need to wrap around to 0. Otherwise, we increment.
@@ -159,7 +142,7 @@ def insert_queue(
len_decr,
(
pifo.reg_store(hot, og_hot.out)
if not round_robin
if not is_round_robin
else ast.Empty
# If we are not generating a round-robin PIFO,
# we are generating a strict PIFO.
@@ -173,8 +156,10 @@ def insert_queue(
raise_err, # The queue is full: overflow.
[ # The queue is not full. Proceed.
lower_err,
# flow := flow of incoming packet
infer_flow,
# We'll push to the subqueue that the value belongs to.
invoke_subqueues_value_guard,
invoke_subqueues_flow_guard,
# If all went well, we'll increment the length of the queue.
cb.if_with(err_is_low, len_incr),
],
@@ -188,36 +173,3 @@ def insert_queue(
)

return pifo


def generate(prog, numflows, roundrobin):
"""Top-level function to build the program."""

if numflows == 2:
boundaries = [0, 200, 400]
order = [1, 0]
elif numflows == 3:
boundaries = [0, 133, 266, 400]
order = [1, 2, 0]
elif numflows == 4:
boundaries = [0, 100, 200, 300, 400]
order = [3, 0, 2, 1]
elif numflows == 5:
boundaries = [0, 80, 160, 240, 320, 400]
order = [0, 1, 2, 3, 4]
elif numflows == 6:
boundaries = [0, 66, 100, 200, 220, 300, 400]
order = [3, 1, 5, 2, 4, 0]
elif numflows == 7:
boundaries = [0, 50, 100, 150, 200, 250, 300, 400]
order = [0, 1, 2, 3, 4, 5, 6]
else:
raise ValueError("Unsupported number of flows")

fifo_queue = fifo.insert_fifo(prog, "fifo", QUEUE_LEN_FACTOR)
subqueues = [fifo_queue] * numflows
pifo = insert_queue(
prog, "pifo", subqueues, boundaries, numflows, order, roundrobin
)

return pifo
39 changes: 14 additions & 25 deletions frontends/queues/tests/complex_tree_test.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
import queues.queue_call as qc
import queues.strict_or_rr as strict_or_rr
import queues.fifo as fifo
import queues.flow_inference as fi

# This complex tree has the shape rr(strict(A, B, C), rr(D, E, F), strict(G, H))

@@ -16,41 +17,29 @@ def build():

fifo_queue = fifo.insert_fifo(prog, "fifo")

fi_strict1 = fi.insert_boundary_flow_inference(prog, "fi_strict1", [44, 88, 133])
pifo_strict1 = strict_or_rr.insert_queue(
prog,
"pifo_strict1",
[fifo_queue, fifo_queue, fifo_queue],
[0, 44, 88, 133],
3,
[0, 1, 2],
False,
[fifo_queue, fifo_queue, fifo_queue],
fi_strict1,
order=[0, 1, 2],
)

fi_rr = fi.insert_boundary_flow_inference(prog, "fi_rr", [177, 221, 266])
pifo_rr = strict_or_rr.insert_queue(
prog,
"pifo_rr",
[fifo_queue, fifo_queue, fifo_queue],
[133, 177, 221, 266],
3,
[0, 1, 2],
True,
prog, "pifo_rr", True, [fifo_queue, fifo_queue, fifo_queue], fi_rr
)

fi_strict2 = fi.insert_boundary_flow_inference(prog, "fi_strict2", [333, 400])
pifo_strict2 = strict_or_rr.insert_queue(
prog,
"pifo_strict2",
[fifo_queue, fifo_queue],
[266, 333, 400],
2,
[0, 1],
False,
prog, "pifo_strict2", False, [fifo_queue, fifo_queue], fi_strict2, order=[0, 1]
)

fi_root = fi.insert_boundary_flow_inference(prog, "fi_root", [133, 266, 400])
pifo_root = strict_or_rr.insert_queue(
prog,
"pifo_root",
[pifo_strict1, pifo_rr, pifo_strict2],
[0, 133, 266, 400],
3,
[],
True,
prog, "pifo_root", True, [pifo_strict1, pifo_rr, pifo_strict2], fi_root
)

qc.insert_main(prog, pifo_root, num_cmds, keepgoing=keepgoing)
15 changes: 13 additions & 2 deletions frontends/queues/tests/pifo_tree_test.py
Original file line number Diff line number Diff line change
@@ -4,20 +4,31 @@
import calyx.builder as cb
import queues.queue_call as qc
import queues.strict_or_rr as strict_or_rr
import queues.flow_inference as fi


def build():
"""Top-level function to build the program."""
num_cmds = int(sys.argv[1])
keepgoing = "--keepgoing" in sys.argv
prog = cb.Builder()

fifo_queue = fifo.insert_fifo(prog, "fifo")

flow_infer_red = fi.insert_boundary_flow_inference(
prog, "flow_infer_red", [100, 200]
)
pifo_red = strict_or_rr.insert_queue(
prog, "pifo_red", [fifo_queue, fifo_queue], [0, 100, 200], 2, [], True
prog, "pifo_red", True, [fifo_queue, fifo_queue], flow_infer_red
)

flow_infer_root = fi.insert_boundary_flow_inference(
prog, "flow_infer_root", [200, 400]
)
pifo_root = strict_or_rr.insert_queue(
prog, "pifo_root", [pifo_red, fifo_queue], [0, 200, 400], 2, [], True
prog, "pifo_root", True, [pifo_red, fifo_queue], flow_infer_root
)

qc.insert_main(prog, pifo_root, num_cmds, keepgoing=keepgoing)
return prog.program

25 changes: 22 additions & 3 deletions frontends/queues/tests/round_robin/rr_2flow_test.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import sys
import calyx.builder as cb
import queues.queue_call as qc
from queues.strict_or_rr import generate
import queues.sim_pcap as sp
import queues.strict_or_rr as st_or_rr
import queues.fifo as fifo
import queues.flow_inference as fi

NUMFLOWS = 2


if __name__ == "__main__":
"""Invoke the top-level function to build the program, with 2 flows."""
num_cmds = int(sys.argv[1])
keepgoing = "--keepgoing" in sys.argv
sim_pcap = "--sim-pcap" in sys.argv

prog = cb.Builder()
pifo = generate(prog, 2, True)
qc.insert_main(prog, pifo, num_cmds, keepgoing=keepgoing)

fifo_queue = fifo.insert_fifo(prog, "fifo")
subqueues = [fifo_queue] * NUMFLOWS
if sim_pcap:
flow_infer = fi.insert_tuple_flow_inference(prog, "flow_inference", NUMFLOWS)
pifo = st_or_rr.insert_queue(prog, "pifo", True, subqueues, flow_infer)
sp.insert_main(prog, pifo, num_cmds, NUMFLOWS)
else:
boundaries = [200, 400]
flow_infer = fi.insert_boundary_flow_inference(
prog, "flow_inference", boundaries
)
pifo = st_or_rr.insert_queue(prog, "pifo", True, subqueues, flow_infer)
qc.insert_main(prog, pifo, num_cmds, keepgoing=keepgoing)

prog.program.emit()
25 changes: 22 additions & 3 deletions frontends/queues/tests/round_robin/rr_3flow_test.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import sys
import calyx.builder as cb
import queues.queue_call as qc
from queues.strict_or_rr import generate
import queues.sim_pcap as sp
import queues.strict_or_rr as st_or_rr
import queues.fifo as fifo
import queues.flow_inference as fi

NUMFLOWS = 3


if __name__ == "__main__":
"""Invoke the top-level function to build the program, with 3 flows."""
num_cmds = int(sys.argv[1])
keepgoing = "--keepgoing" in sys.argv
sim_pcap = "--sim-pcap" in sys.argv

prog = cb.Builder()
pifo = generate(prog, 3, True)
qc.insert_main(prog, pifo, num_cmds, keepgoing=keepgoing)

fifo_queue = fifo.insert_fifo(prog, "fifo")
subqueues = [fifo_queue] * NUMFLOWS
if sim_pcap:
flow_infer = fi.insert_tuple_flow_inference(prog, "flow_inference", NUMFLOWS)
pifo = st_or_rr.insert_queue(prog, "pifo", True, subqueues, flow_infer)
sp.insert_main(prog, pifo, num_cmds, NUMFLOWS)
else:
boundaries = [133, 266, 400]
flow_infer = fi.insert_boundary_flow_inference(
prog, "flow_inference", boundaries
)
pifo = st_or_rr.insert_queue(prog, "pifo", True, subqueues, flow_infer)
qc.insert_main(prog, pifo, num_cmds, keepgoing=keepgoing)

prog.program.emit()
25 changes: 22 additions & 3 deletions frontends/queues/tests/round_robin/rr_4flow_test.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import sys
import calyx.builder as cb
import queues.queue_call as qc
from queues.strict_or_rr import generate
import queues.sim_pcap as sp
import queues.strict_or_rr as st_or_rr
import queues.fifo as fifo
import queues.flow_inference as fi

NUMFLOWS = 4


if __name__ == "__main__":
"""Invoke the top-level function to build the program, with 4 flows."""
num_cmds = int(sys.argv[1])
keepgoing = "--keepgoing" in sys.argv
sim_pcap = "--sim-pcap" in sys.argv

prog = cb.Builder()
pifo = generate(prog, 4, True)
qc.insert_main(prog, pifo, num_cmds, keepgoing=keepgoing)

fifo_queue = fifo.insert_fifo(prog, "fifo")
subqueues = [fifo_queue] * NUMFLOWS
if sim_pcap:
flow_infer = fi.insert_tuple_flow_inference(prog, "flow_inference", NUMFLOWS)
pifo = st_or_rr.insert_queue(prog, "pifo", True, subqueues, flow_infer)
sp.insert_main(prog, pifo, num_cmds, NUMFLOWS)
else:
boundaries = [100, 200, 300, 400]
flow_infer = fi.insert_boundary_flow_inference(
prog, "flow_inference", boundaries
)
pifo = st_or_rr.insert_queue(prog, "pifo", True, subqueues, flow_infer)
qc.insert_main(prog, pifo, num_cmds, keepgoing=keepgoing)

prog.program.emit()
Loading