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

Analytical FIFO sizing #1185

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
3 changes: 2 additions & 1 deletion src/finn/builder/build_dataflow_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class AutoFIFOSizingMethod(str, Enum):
"Select the type of automatic FIFO sizing strategy."

CHARACTERIZE = "characterize"
CHARACTERIZE_ANALYTIC = "characterize_analytic"
LARGEFIFO_RTLSIM = "largefifo_rtlsim"


Expand Down Expand Up @@ -116,9 +117,9 @@ class VerificationStepType(str, Enum):
"step_apply_folding_config",
"step_minimize_bit_width",
"step_generate_estimate_reports",
"step_set_fifo_depths",
"step_hw_codegen",
"step_hw_ipgen",
"step_set_fifo_depths",
"step_create_stitched_ip",
"step_measure_rtlsim_performance",
"step_out_of_context_synthesis",
Expand Down
32 changes: 28 additions & 4 deletions src/finn/builder/build_dataflow_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,18 +548,36 @@ def step_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig):
`GiveUniqueNodeNames`.
"""

print("ENTERED STEP FIFO DEPTHS")
if cfg.auto_fifo_depths:
if cfg.auto_fifo_strategy == "characterize":
if cfg.auto_fifo_strategy in ["characterize_analytic", "characterize"]:
model = model.transform(InsertDWC())
model = model.transform(SpecializeLayers(cfg._resolve_fpga_part()))
model = model.transform(GiveUniqueNodeNames())

if cfg.auto_fifo_strategy == "characterize_analytic":
# RTL sim only the nodes which are not supported right now with
# analytic characteristic derivations.
# To do this, we first check if the characteristic
# function exists for each node. If yes, we make sure PrepareIP and HLSSynthIP
# do not generate code for them. We unset the flags afterwards
# so that a repeat call to SynthIP and PrepareIP will indeed generate the cpp code.
for node in model.graph.node:
node_inst = getCustomOp(node)
prepare_kwargs_for_characteristic_fx = getattr(
node_inst, "prepare_kwargs_for_characteristic_fx", None
)
if callable(prepare_kwargs_for_characteristic_fx):
node_inst.set_nodeattr("ipgen_ignore", True)

model = model.transform(
PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period())
)
model = model.transform(HLSSynthIP())
model = model.transform(PrepareRTLSim())
model = model.transform(AnnotateCycles())
period = model.analysis(dataflow_performance)["max_cycles"] + 10

period = int(model.analysis(dataflow_performance)["max_cycles"] * 3)
model = model.transform(DeriveCharacteristic(period))
model = model.transform(DeriveFIFOSizes())
model = model.transform(
Expand Down Expand Up @@ -623,6 +641,7 @@ def step_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig):
"depth_trigger_uram",
"depth_trigger_bram",
]

extract_model_config_to_json(model, cfg.output_dir + "/final_hw_config.json", hw_attrs)

# perform FIFO splitting and shallow FIFO removal only after the final config
Expand All @@ -632,10 +651,15 @@ def step_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig):
model = model.transform(SplitLargeFIFOs())
model = model.transform(RemoveShallowFIFOs())

# FIFO sizing is done, we can allow all ipgen again
for node in model.graph.node:
node_inst = getCustomOp(node)
node_inst.set_nodeattr("ipgen_ignore", False)

# after FIFOs are ready to go, call PrepareIP and HLSSynthIP again
# this will only run for the new nodes (e.g. FIFOs and DWCs)
model = model.transform(PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period()))
model = model.transform(HLSSynthIP())
# model = model.transform(PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period()))
# model = model.transform(HLSSynthIP())
return model


Expand Down
114 changes: 114 additions & 0 deletions src/finn/custom_op/fpgadataflow/channelwise_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,117 @@ def execute_node(self, context, graph):
sess = rt.InferenceSession(model_func.SerializeToString())
result = sess.run(None, idict)
context[node.output[0]] = np.asarray(result, dtype=np.float32).reshape(oshape)

def prepare_kwargs_for_characteristic_fx(self):
# key parameters
PE = self.get_nodeattr("PE")
NumChannels = self.get_nodeattr("NumChannels")
NF = int(NumChannels / PE)
dim = np.prod(self.get_folded_output_shape()[1:-1])
# assert True == False
kwargs = (NF, dim)

# assert True==False

return kwargs

def characteristic_fx_input(self, txns, cycles, counter, kwargs):
# Compute one period of the input characteristic function

(NF, dim) = kwargs

for k in range(dim):
txns.append(counter)
counter += 1
cycles += 1

#
return txns, cycles, counter

def characteristic_fx_output(self, txns, cycles, counter, kwargs):
# Compute one period of the output characteristic function

(NF, dim) = kwargs

for k in range(dim):
txns.append(counter)
counter += 1
cycles += 1

return txns, cycles, counter

def derive_characteristic_fxns(self, period):
n_inps = np.prod(self.get_folded_input_shape()[:-1])
io_dict = {
"inputs": {
"in0": [0 for i in range(n_inps)],
},
"outputs": {"out": []},
}

ignore = self.get_nodeattr("ipgen_ignore")
if ignore is False: # this node is being derived using RTLSIM
# RTL-based flow
super().derive_characteristic_fxns(period, override_rtlsim_dict=io_dict)
return

# Analytical flow

txns_in = {key: [] for (key, value) in io_dict["inputs"].items() if "in" in key}
txns_out = {key: [] for (key, value) in io_dict["outputs"].items() if "out" in key}

all_txns_in = np.empty((len(txns_in.keys()), 2 * period), dtype=np.int32)
all_txns_out = np.empty((len(txns_out.keys()), 2 * period), dtype=np.int32)

self.set_nodeattr("io_chrc_period", period)

txn_in = []
txn_out = []

# INPUT

counter = 0
padding = 0

kwargs = self.prepare_kwargs_for_characteristic_fx()

# first period
cycles = 0
txn_in, cycles, counter = self.characteristic_fx_input(txn_in, cycles, counter, kwargs)

txn_in += [counter] * (period - cycles)
padding += period * -cycles

# second period
cycles = period
txn_in, cycles, counter = self.characteristic_fx_input(txn_in, cycles, counter, kwargs)

txn_in += [counter] * (period * 2 - cycles)
padding += period * 2 - cycles

# final assignments
all_txns_in[0, :] = np.array(txn_in)
self.set_nodeattr("io_chrc_in", all_txns_in)
self.set_nodeattr("io_chrc_pads_in", padding)

# OUTPUT

counter = 0
cycles = 0
padding = 0

txn_out, cycles, counter = self.characteristic_fx_output(txn_out, cycles, counter, kwargs)

txn_out += [counter] * (period - cycles)
padding += period * -cycles

cycles = period

txn_out, cycles, counter = self.characteristic_fx_output(txn_out, cycles, counter, kwargs)

txn_out += [counter] * (period * 2 - cycles)
padding += period * 2 - cycles

all_txns_out[0, :] = np.array(txn_out)
self.set_nodeattr("io_chrc_out", all_txns_out)
self.set_nodeattr("io_chrc_pads_out", padding)
Loading
Loading