Skip to content
Snippets Groups Projects
Commit bea93338 authored by Yaman Umuroglu's avatar Yaman Umuroglu
Browse files

[ResUtil] handle SDPs with some recursion

parent 493f7b29
No related branches found
No related tags found
No related merge requests found
......@@ -30,15 +30,20 @@ import os
import xml.etree.ElementTree as ET
from finn.transformation.move_reshape import _is_fpgadataflow_node
from finn.core.modelwrapper import ModelWrapper
from finn.custom_op.registry import getCustomOp
def post_synth_res(model):
def post_synth_res(model, override_synth_report_filename=None):
"""Extracts the FPGA resource results from the Vivado synthesis.
Returns {node name : resources_dict}."""
res_dict = {}
synth_report_filename = model.get_metadata_prop("vivado_synth_rpt")
if override_synth_report_filename is not None:
synth_report_filename = override_synth_report_filename
else:
synth_report_filename = model.get_metadata_prop("vivado_synth_rpt")
if os.path.isfile(synth_report_filename):
tree = ET.parse(synth_report_filename)
root = tree.getroot()
......@@ -51,30 +56,35 @@ def post_synth_res(model):
for node in model.graph.node:
if _is_fpgadataflow_node(node):
row = root.findall(".//*[@contents='%s']/.." % node.name)
if row != []:
node_dict = {}
row = row[0].getchildren()
""" Expected XML structure:
<tablerow class="" suppressoutput="0" wordwrap="0">
<tableheader class="" contents="Instance" halign="3" width="-1"/>
<tableheader class="" contents="Module" halign="3" width="-1"/>
<tableheader class="" contents="Total LUTs" halign="3" width="-1"/>
<tableheader class="" contents="Logic LUTs" halign="3" width="-1"/>
<tableheader class="" contents="LUTRAMs" halign="3" width="-1"/>
<tableheader class="" contents="SRLs" halign="3" width="-1"/>
<tableheader class="" contents="FFs" halign="3" width="-1"/>
<tableheader class="" contents="RAMB36" halign="3" width="-1"/>
<tableheader class="" contents="RAMB18" halign="3" width="-1"/>
<tableheader class="" contents="DSP48 Blocks" halign="3" width="-1"/>
</tablerow>
"""
node_dict["LUT"] = int(row[2].attrib["contents"])
node_dict["SRL"] = int(row[5].attrib["contents"])
node_dict["FF"] = int(row[6].attrib["contents"])
node_dict["BRAM_36K"] = int(row[7].attrib["contents"])
node_dict["BRAM_18K"] = int(row[8].attrib["contents"])
node_dict["DSP48"] = int(row[9].attrib["contents"])
res_dict[node.name] = node_dict
if node.op_type == "StreamingDataflowPartition":
sdp_model = ModelWrapper(getCustomOp(node).get_nodeattr("model"))
sdp_res_dict = post_synth_res(sdp_model, synth_report_filename)
res_dict.update(sdp_res_dict)
else:
row = root.findall(".//*[@contents='%s']/.." % node.name)
if row != []:
node_dict = {}
row = row[0].getchildren()
""" Expected XML structure:
<tablerow class="" suppressoutput="0" wordwrap="0">
<tableheader class="" contents="Instance" halign="3" width="-1"/>
<tableheader class="" contents="Module" halign="3" width="-1"/>
<tableheader class="" contents="Total LUTs" halign="3" width="-1"/>
<tableheader class="" contents="Logic LUTs" halign="3" width="-1"/>
<tableheader class="" contents="LUTRAMs" halign="3" width="-1"/>
<tableheader class="" contents="SRLs" halign="3" width="-1"/>
<tableheader class="" contents="FFs" halign="3" width="-1"/>
<tableheader class="" contents="RAMB36" halign="3" width="-1"/>
<tableheader class="" contents="RAMB18" halign="3" width="-1"/>
<tableheader class="" contents="DSP48 Blocks" halign="3" width="-1"/>
</tablerow>
"""
node_dict["LUT"] = int(row[2].attrib["contents"])
node_dict["SRL"] = int(row[5].attrib["contents"])
node_dict["FF"] = int(row[6].attrib["contents"])
node_dict["BRAM_36K"] = int(row[7].attrib["contents"])
node_dict["BRAM_18K"] = int(row[8].attrib["contents"])
node_dict["DSP48"] = int(row[9].attrib["contents"])
res_dict[node.name] = node_dict
return res_dict
......@@ -32,6 +32,8 @@ from finn.transformation.move_reshape import _is_fpgadataflow_node
from finn.analysis.fpgadataflow.res_estimation import res_estimation
from finn.analysis.fpgadataflow.hls_synth_res_estimation import hls_synth_res_estimation
from finn.analysis.fpgadataflow.post_synth_res import post_synth_res
from finn.core.modelwrapper import ModelWrapper
from finn.custom_op.registry import getCustomOp
class AnnotateResources(Transformation):
......@@ -44,9 +46,10 @@ class AnnotateResources(Transformation):
chosen mode (e.g. HLSSynthIP for hls) was previously run.
"""
def __init__(self, mode):
def __init__(self, mode, override_res_dict=None):
super().__init__()
self.mode = mode
self.res_dict = override_res_dict
def apply(self, model):
graph = model.graph
......@@ -58,10 +61,34 @@ class AnnotateResources(Transformation):
res_fxn = post_synth_res
else:
raise Exception("Unrecognized mode for AnnotateResources")
res_dict = model.analysis(res_fxn)
if self.res_dict is None:
self.res_dict = model.analysis(res_fxn)
children_dict = {}
# annotate node resources
for node in graph.node:
if _is_fpgadataflow_node(node):
if node.name in self.res_dict.keys():
op_inst = registry.getCustomOp(node)
op_inst.set_nodeattr(
"res_" + self.mode, str(self.res_dict[node.name])
)
children_dict[node.name] = self.res_dict[node.name]
elif node.op_type == "StreamingDataflowPartition":
# recurse into model to manually annotate per-layer resources
sdp_model_filename = getCustomOp(node).get_nodeattr("model")
sdp_model = ModelWrapper(sdp_model_filename)
sdp_model = sdp_model.transform(
AnnotateResources(self.mode, self.res_dict)
)
sdp_dict = sdp_model.get_metadata_prop("res_total_" + self.mode)
# save transformed model
sdp_model.save(sdp_model_filename)
# set res attribute for sdp node
getCustomOp(node).set_nodeattr("res_" + self.mode, str(sdp_dict))
children_dict[node.name] = sdp_dict
total_dict = {}
for lname in res_dict.keys():
layer_res_dict = res_dict[lname]
for lname in children_dict.keys():
layer_res_dict = self.res_dict[lname]
for r_type in layer_res_dict.keys():
r_amount = layer_res_dict[r_type]
r_amount = float(r_amount)
......@@ -73,9 +100,4 @@ class AnnotateResources(Transformation):
if "efficiency" in k:
total_dict[k] = total_dict[k] / len(graph.node)
model.set_metadata_prop("res_total_" + self.mode, str(total_dict))
for node in graph.node:
if _is_fpgadataflow_node(node) and node.name in res_dict.keys():
op_inst = registry.getCustomOp(node)
op_inst.set_nodeattr("res_" + self.mode, str(res_dict[node.name]))
return (model, False)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment