From fef84fe0d46fce63f79b4f1292452b1ba2d57866 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu <maltanar@gmail.com> Date: Fri, 27 Jan 2023 17:52:10 +0100 Subject: [PATCH] [FIFO] make FIFO insertions act more consistently - do not set in/outFIFODepths attrs to 0 after setting - do not set in/outFIFODepths attrs to max() in InsertFIFO - special handling of first/last FIFO depths for characterization --- src/finn/builder/build_dataflow_steps.py | 8 +- .../fpgadataflow/derive_characteristic.py | 13 +- .../fpgadataflow/insert_fifo.py | 161 +++++++++--------- .../fpgadataflow/set_fifo_depths.py | 55 +++++- 4 files changed, 151 insertions(+), 86 deletions(-) diff --git a/src/finn/builder/build_dataflow_steps.py b/src/finn/builder/build_dataflow_steps.py index 956b4fd3b..ce0ffb477 100644 --- a/src/finn/builder/build_dataflow_steps.py +++ b/src/finn/builder/build_dataflow_steps.py @@ -527,7 +527,9 @@ def step_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig): model = model.transform(DeriveFIFOSizes()) model = model.transform( InsertFIFO( - vivado_ram_style=cfg.large_fifo_mem_style, max_qsrl_depth=256 + vivado_ram_style=cfg.large_fifo_mem_style, + max_qsrl_depth=256, + create_shallow_fifos=True, ) ) model = model.transform(GiveUniqueNodeNames()) @@ -549,6 +551,8 @@ def step_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig): force_python_sim=force_python_sim, ) ) + # InsertAndSetFIFODepths internally removes any shallow FIFOs + # so no need to call RemoveShallowFIFOs here else: assert "Unsupported auto_fifo_strategy: " + cfg.auto_fifo_strategy else: @@ -575,6 +579,8 @@ def step_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig): "resType", "mem_mode", "runtime_writeable_weights", + "inFIFODepths", + "outFIFODepths", ] extract_model_config_to_json( model, cfg.output_dir + "/final_hw_config.json", hw_attrs diff --git a/src/finn/transformation/fpgadataflow/derive_characteristic.py b/src/finn/transformation/fpgadataflow/derive_characteristic.py index f783f7ae7..67eb96995 100644 --- a/src/finn/transformation/fpgadataflow/derive_characteristic.py +++ b/src/finn/transformation/fpgadataflow/derive_characteristic.py @@ -134,8 +134,9 @@ class DeriveFIFOSizes(NodeLocalTransformation): NodeLocalTransformation for more details. """ - def __init__(self, num_workers=None): + def __init__(self, num_workers=None, io_fifo_depth=32): super().__init__(num_workers=num_workers) + self.io_fifo_depth = io_fifo_depth def applyNodeLocal(self, node): op_type = node.op_type @@ -161,7 +162,7 @@ class DeriveFIFOSizes(NodeLocalTransformation): if cons_node is None: # could be final node, will be overridden if so # need an entry in the list anyway - out_fifo_depths.append(2) + out_fifo_depths.append(self.io_fifo_depth) continue cons = registry.getCustomOp(cons_node) cons_chrc = cons.get_nodeattr("io_chrc_in")[0] @@ -182,6 +183,14 @@ class DeriveFIFOSizes(NodeLocalTransformation): # for each tensor prod.set_nodeattr("outFIFODepths", out_fifo_depths) + # finally, check node inputs to ensure FIFOs are added to + # any top-level inputs (at least self.io_fifo_depth deep) + in_fifo_depths = prod.get_nodeattr("inFIFODepths") + for (i, input_name) in enumerate(node.input): + if input_name in [x.name for x in model.graph.input]: + in_fifo_depths[i] = max(self.io_fifo_depth, in_fifo_depths[i]) + prod.set_nodeattr("inFIFODepths", in_fifo_depths) + except KeyError: # exception if op_type is not supported raise Exception( diff --git a/src/finn/transformation/fpgadataflow/insert_fifo.py b/src/finn/transformation/fpgadataflow/insert_fifo.py index 0546643d1..50da9cdf1 100644 --- a/src/finn/transformation/fpgadataflow/insert_fifo.py +++ b/src/finn/transformation/fpgadataflow/insert_fifo.py @@ -177,14 +177,9 @@ class InsertFIFO(Transformation): for idx, inp in enumerate(consumer.input): if inp == output_name: consumer.input[idx] = fifo_output_tensor.name - # ensure created FIFO depth is reflected on both sides - odepths = n0.get_nodeattr("outFIFODepths") - odepths[idx_out] = fifo_depth - n0.set_nodeattr("outFIFODepths", odepths) - idepths = n1.get_nodeattr("inFIFODepths") - idepths[idx_inp] = fifo_depth - n1.set_nodeattr("inFIFODepths", idepths) - + # removed setting of node attributes based on created + # FIFO sizes here, better to preserve original attrs + # as they are. graph_modified = True if graph_modified is False: @@ -204,41 +199,48 @@ class InsertFIFO(Transformation): dtype = n0.get_input_datatype(inp_ind) fifo_depth = n0.get_nodeattr("inFIFODepths")[inp_ind] - if fifo_depth <= 2: - warnings.warn("Overriding input FIFO depth to 32") - fifo_depth = 32 - - # create fifo node - fifo_output_tensor = oh.make_tensor_value_info( - model.make_new_valueinfo_name(), - TensorProto.FLOAT, - n0.get_normal_input_shape(), - ) - graph.value_info.append(fifo_output_tensor) - model.set_tensor_datatype(fifo_output_tensor.name, dtype) - - if self.max_qsrl_depth is None or fifo_depth <= self.max_qsrl_depth: - impl_style = "rtl" + if fifo_depth > 2 or self.create_shallow_fifos: + # create fifo node + fifo_output_tensor = oh.make_tensor_value_info( + model.make_new_valueinfo_name(), + TensorProto.FLOAT, + n0.get_normal_input_shape(), + ) + graph.value_info.append(fifo_output_tensor) + model.set_tensor_datatype(fifo_output_tensor.name, dtype) + + if ( + self.max_qsrl_depth is None + or fifo_depth <= self.max_qsrl_depth + ): + impl_style = "rtl" + else: + impl_style = "vivado" + + fifo_node = oh.make_node( + "StreamingFIFO", + [n_input], + [fifo_output_tensor.name], + domain="finn.custom_op.fpgadataflow", + backend="fpgadataflow", + depth=fifo_depth, + folded_shape=fld_shape, + dataType=str(dtype.name), + impl_style=impl_style, + ram_style=self.vivado_ram_style, + ) + # insert fifo + graph.node.insert(0, fifo_node) + + # set fifo output tensor as new input tensor of second node + first_node.input[inp_ind] = fifo_output_tensor.name else: - impl_style = "vivado" - - fifo_node = oh.make_node( - "StreamingFIFO", - [n_input], - [fifo_output_tensor.name], - domain="finn.custom_op.fpgadataflow", - backend="fpgadataflow", - depth=fifo_depth, - folded_shape=fld_shape, - dataType=str(dtype.name), - impl_style=impl_style, - ram_style=self.vivado_ram_style, - ) - # insert fifo - graph.node.insert(0, fifo_node) - - # set fifo output tensor as new input tensor of second node - first_node.input[inp_ind] = fifo_output_tensor.name + warnings.warn( + """Input FIFO for %s has depth %d and won't + be created. This may cause RTL simulation issues. + """ + % (graph_in_name, fifo_depth) + ) # insert FIFO as last node, except when last node is DMA graph_out_names = [x.name for x in model.graph.output] @@ -259,40 +261,47 @@ class InsertFIFO(Transformation): dtype = n0.get_output_datatype(out_ind) fifo_depth = n0.get_nodeattr("outFIFODepths")[out_ind] - if fifo_depth <= 2: - warnings.warn("Overriding output FIFO depth to 32") - fifo_depth = 32 - - # create fifo node - fifo_input_tensor = oh.make_tensor_value_info( - model.make_new_valueinfo_name(), - TensorProto.FLOAT, - n0.get_normal_output_shape(), - ) - graph.value_info.append(fifo_input_tensor) - model.set_tensor_datatype(fifo_input_tensor.name, dtype) - - if self.max_qsrl_depth is None or fifo_depth <= self.max_qsrl_depth: - impl_style = "rtl" + if fifo_depth > 2 or self.create_shallow_fifos: + # create fifo node + fifo_input_tensor = oh.make_tensor_value_info( + model.make_new_valueinfo_name(), + TensorProto.FLOAT, + n0.get_normal_output_shape(), + ) + graph.value_info.append(fifo_input_tensor) + model.set_tensor_datatype(fifo_input_tensor.name, dtype) + + if ( + self.max_qsrl_depth is None + or fifo_depth <= self.max_qsrl_depth + ): + impl_style = "rtl" + else: + impl_style = "vivado" + + fifo_node = oh.make_node( + "StreamingFIFO", + [fifo_input_tensor.name], + [graph_out_name], + domain="finn.custom_op.fpgadataflow", + backend="fpgadataflow", + depth=fifo_depth, + folded_shape=fld_shape, + dataType=str(dtype.name), + impl_style=impl_style, + ram_style=self.vivado_ram_style, + ) + # insert fifo + graph.node.append(fifo_node) + + # set fifo output tensor as new input tensor of second node + final_node.output[0] = fifo_input_tensor.name else: - impl_style = "vivado" - - fifo_node = oh.make_node( - "StreamingFIFO", - [fifo_input_tensor.name], - [graph_out_name], - domain="finn.custom_op.fpgadataflow", - backend="fpgadataflow", - depth=fifo_depth, - folded_shape=fld_shape, - dataType=str(dtype.name), - impl_style=impl_style, - ram_style=self.vivado_ram_style, - ) - # insert fifo - graph.node.append(fifo_node) - - # set fifo output tensor as new input tensor of second node - final_node.output[0] = fifo_input_tensor.name + warnings.warn( + """Output FIFO for %s has depth %d and won't + be created. This may cause RTL simulation issues. + """ + % (graph_out_name, fifo_depth) + ) return (model, graph_modified) diff --git a/src/finn/transformation/fpgadataflow/set_fifo_depths.py b/src/finn/transformation/fpgadataflow/set_fifo_depths.py index 8f766bcdb..9282d399f 100644 --- a/src/finn/transformation/fpgadataflow/set_fifo_depths.py +++ b/src/finn/transformation/fpgadataflow/set_fifo_depths.py @@ -224,7 +224,7 @@ class InsertAndSetFIFODepths(Transformation): - run through rtlsim with stream of multiple random input images (to fill pipeline) - keep track of observed maximum occupancy for each FIFO during rtlsim - when sim finished, update each FIFO depth to maximum observed occupancy - and set inFIFODepths/outFIFODepths attrs to 0 on relevant nodes + and set inFIFODepths/outFIFODepths attrs to that depth as well """ @@ -289,7 +289,7 @@ class InsertAndSetFIFODepths(Transformation): # insert stream infrastructure (DWC/FIFO) model = model.transform(InsertDWC()) - model = model.transform(InsertFIFO()) + model = model.transform(InsertFIFO(create_shallow_fifos=True)) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) @@ -416,11 +416,7 @@ class InsertAndSetFIFODepths(Transformation): reset_implementation(node_inst) del fifos[node.name] else: - inst = getCustomOp(node) - ifd = inst.get_nodeattr("inFIFODepths") - ofd = inst.get_nodeattr("outFIFODepths") - inst.set_nodeattr("inFIFODepths", [0] * len(ifd)) - inst.set_nodeattr("outFIFODepths", [0] * len(ofd)) + # (removed setting of node FIFO size attributes to 0 here) # for every extw node we changed from external to decoupled, # change back and reset implementation if node.op_type in extw_optypes: @@ -442,4 +438,49 @@ class InsertAndSetFIFODepths(Transformation): # remove shallow FIFOs model = model.transform(RemoveShallowFIFOs()) + # reflect final values in attributes + for node in model.graph.node: + if node.op_type != "StreamingFIFO": + node_inst = getCustomOp(node) + fifodepth_in = [] + for node_inp in node.input: + prod = model.find_producer(node_inp) + if prod is None: + # no producer for this input + if node_inp in [x.name for x in model.graph.input]: + # top-level input with no FIFO + fifodepth_in.append(0) + else: + # FIFO depth attr applies only to dynamic attributes + pass + else: + # there is a producer for this input + if prod.op_type == "StreamingFIFO": + prod_inst = getCustomOp(prod) + fifodepth_in.append(prod_inst.get_nodeattr("depth")) + else: + # explicitly no FIFO on this dynamic input + fifodepth_in.append(0) + fifodepth_out = [] + for node_out in node.output: + cons = model.find_consumer(node_out) + if cons is None: + # no consumer for this output + if node_out in [x.name for x in model.graph.output]: + # top-level output with no FIFO + fifodepth_out.append(0) + else: + # FIFO depth attr applies only to dynamic attributes + pass + else: + # there is a consumer for this input + if cons.op_type == "StreamingFIFO": + cons_inst = getCustomOp(cons) + fifodepth_out.append(cons_inst.get_nodeattr("depth")) + else: + # explicitly no FIFO on this dynamic output + fifodepth_out.append(0) + node_inst.set_nodeattr("inFIFODepths", fifodepth_in) + node_inst.set_nodeattr("outFIFODepths", fifodepth_out) + return (model, False) -- GitLab