diff --git a/src/finn/transformation/fpgadataflow/make_pynq_proj.py b/src/finn/transformation/fpgadataflow/make_pynq_proj.py deleted file mode 100644 index 5e45d6f230503668a15d784e3c6afa45560fe004..0000000000000000000000000000000000000000 --- a/src/finn/transformation/fpgadataflow/make_pynq_proj.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright (c) 2020, Xilinx -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of FINN nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import warnings -import subprocess - -from finn.custom_op.registry import getCustomOp -from finn.transformation import Transformation -from finn.util.basic import get_by_name, make_build_dir, roundup_to_integer_multiple - -from . import templates - - -class MakePYNQProject(Transformation): - """Create a Vivado PYNQ overlay project (including the shell infrastructure) - from the already-stitched IP block for this graph. - All nodes in the graph must have the fpgadataflow backend attribute, - and the CreateStitchedIP transformation must have been previously run on - the graph. - - Outcome if successful: sets the vivado_pynq_proj attribute in the ONNX - ModelProto's metadata_props field, with the created project dir as the - value. - """ - - def __init__(self, platform): - super().__init__() - self.platform = platform - - def apply(self, model): - pynq_shell_path = os.environ["PYNQSHELL_PATH"] - if not os.path.isdir(pynq_shell_path): - raise Exception("Ensure the PYNQ-HelloWorld utility repo is cloned.") - ipstitch_path = model.get_metadata_prop("vivado_stitch_proj") - if ipstitch_path is None or (not os.path.isdir(ipstitch_path)): - raise Exception( - "No stitched IPI design found, apply CreateStitchedIP first." - ) - vivado_stitch_vlnv = model.get_metadata_prop("vivado_stitch_vlnv") - if vivado_stitch_vlnv is None: - raise Exception( - "No vlnv for stitched IP found, apply CreateStitchedIP first." - ) - vivado_stitch_ifnames = model.get_metadata_prop("vivado_stitch_ifnames") - if vivado_stitch_ifnames is None: - raise Exception("No IF name metadata found, apply CreateStitchedIP first.") - vivado_stitch_ifnames = eval(vivado_stitch_ifnames) - # recover interface names from dict - self.clk_name = vivado_stitch_ifnames["clk"][0] - self.rst_name = vivado_stitch_ifnames["rst"][0] - self.s_axis_if_name = vivado_stitch_ifnames["s_axis"][0] - self.m_axis_if_name = vivado_stitch_ifnames["m_axis"][0] - self.s_aximm_if_name = vivado_stitch_ifnames["axilite"][0] - - # collect list of all IP dirs - ip_dirs = ["list"] - for node in model.graph.node: - ip_dir_attribute = get_by_name(node.attribute, "ip_path") - assert ( - ip_dir_attribute is not None - ), """Node attribute "ip_path" is - empty. Please run transformation HLSSynth_ipgen first.""" - ip_dir_value = ip_dir_attribute.s.decode("UTF-8") - assert os.path.isdir( - ip_dir_value - ), """The directory that should - contain the generated ip blocks doesn't exist.""" - ip_dirs += [ip_dir_value] - ip_dirs += [ipstitch_path + "/ip"] - ip_dirs_str = "[%s]" % (" ".join(ip_dirs)) - - # extract HLSCustomOp instances to get i/o stream widths - i_tensor_name = model.graph.input[0].name - o_tensor_name = model.graph.output[0].name - first_node = getCustomOp(model.find_consumer(i_tensor_name)) - last_node = getCustomOp(model.find_producer(o_tensor_name)) - i_bits_per_cycle = first_node.get_instream_width() - o_bits_per_cycle = last_node.get_outstream_width() - # ensure i/o is padded to bytes - i_bits_per_cycle_padded = roundup_to_integer_multiple(i_bits_per_cycle, 8) - o_bits_per_cycle_padded = roundup_to_integer_multiple(o_bits_per_cycle, 8) - assert ( - i_bits_per_cycle_padded % 8 == 0 - ), """Padded input bits are not a - multiple of 8.""" - assert ( - o_bits_per_cycle_padded % 8 == 0 - ), """Padded output bits are not a - multiple of 8.""" - in_bytes = i_bits_per_cycle_padded / 8 - out_bytes = o_bits_per_cycle_padded / 8 - in_if_name = self.s_axis_if_name - out_if_name = self.m_axis_if_name - clk_name = self.clk_name - nrst_name = self.rst_name - axi_lite_if_name = self.s_aximm_if_name - vivado_ip_cache = os.getenv("VIVADO_IP_CACHE", default="") - - # create a temporary folder for the project - vivado_pynq_proj_dir = make_build_dir(prefix="vivado_pynq_proj_") - model.set_metadata_prop("vivado_pynq_proj", vivado_pynq_proj_dir) - # filename for the synth utilization report - synth_report_filename = vivado_pynq_proj_dir + "/synth_report.xml" - model.set_metadata_prop("vivado_synth_rpt", synth_report_filename) - # set platform attribute for correct remote execution - model.set_metadata_prop("platform", "zynq") - - # get metadata property clk_ns to calculate clock frequency - clk_ns = float(model.get_metadata_prop("clk_ns")) - if clk_ns not in [5.0, 10.0, 20.0]: - warnings.warn( - """The chosen frequency may lead to failure due to clock divider - constraints.""" - ) - fclk_mhz = 1 / (clk_ns * 0.001) - - ip_config_tcl = templates.ip_config_tcl_template % ( - vivado_pynq_proj_dir, - ip_dirs_str, - vivado_pynq_proj_dir, - synth_report_filename, - vivado_stitch_vlnv, - in_bytes, - out_bytes, - in_if_name, - out_if_name, - clk_name, - nrst_name, - axi_lite_if_name, - vivado_ip_cache, - fclk_mhz, - ) - - with open(vivado_pynq_proj_dir + "/ip_config.tcl", "w") as f: - f.write(ip_config_tcl) - # create a shell script for project creation and synthesis - make_project_sh = vivado_pynq_proj_dir + "/make_project.sh" - working_dir = os.environ["PWD"] - ipcfg = vivado_pynq_proj_dir + "/ip_config.tcl" - with open(make_project_sh, "w") as f: - f.write( - templates.call_pynqshell_makefile_template - % (pynq_shell_path, self.platform, ipcfg, "block_design", working_dir) - ) - synth_project_sh = vivado_pynq_proj_dir + "/synth_project.sh" - with open(synth_project_sh, "w") as f: - f.write( - templates.call_pynqshell_makefile_template - % (pynq_shell_path, self.platform, ipcfg, "bitstream", working_dir) - ) - # call the project creation script - # synthesis script will be called with a separate transformation - bash_command = ["bash", make_project_sh] - process_compile = subprocess.Popen(bash_command, stdout=subprocess.PIPE) - process_compile.communicate() - return (model, False) diff --git a/src/finn/transformation/fpgadataflow/synth_pynq_proj.py b/src/finn/transformation/fpgadataflow/synth_pynq_proj.py deleted file mode 100644 index 7f9bbaf5665f872d4393fa173b60b2cc3a6655e9..0000000000000000000000000000000000000000 --- a/src/finn/transformation/fpgadataflow/synth_pynq_proj.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2020, Xilinx -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of FINN nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import subprocess - -from finn.transformation import Transformation - - -class SynthPYNQProject(Transformation): - """Run synthesis for the PYNQ project for this graph. The MakePYNQProject - transformation must be applied prior to this transformation.""" - - def __init__(self): - super().__init__() - - def apply(self, model): - vivado_pynq_proj_dir = model.get_metadata_prop("vivado_pynq_proj") - if vivado_pynq_proj_dir is None or (not os.path.isdir(vivado_pynq_proj_dir)): - raise Exception("No synthesis project, apply MakePYNQProject first.") - synth_project_sh = vivado_pynq_proj_dir + "/synth_project.sh" - if not os.path.isfile(synth_project_sh): - raise Exception("No synthesis script, apply MakePYNQProject first.") - bash_command = ["bash", synth_project_sh] - process_compile = subprocess.Popen(bash_command, stdout=subprocess.PIPE) - process_compile.communicate() - # set bitfile attribute - model.set_metadata_prop("bitfile", vivado_pynq_proj_dir + "/resizer.bit") - model.set_metadata_prop("hw_handoff", vivado_pynq_proj_dir + "/resizer.hwh") - # TODO pull out synthesis statistics and put them in as attributes - return (model, False) diff --git a/tests/fpgadataflow/test_fpgadataflow_fifo.py b/tests/fpgadataflow/test_fpgadataflow_fifo.py index 8f6f5e2e5fc380d8dc4e5d4413d1503687ca67ae..53de417eac175d8b700e84aecb304895a5942c16 100644 --- a/tests/fpgadataflow/test_fpgadataflow_fifo.py +++ b/tests/fpgadataflow/test_fpgadataflow_fifo.py @@ -2,36 +2,19 @@ import pytest import os from onnx import TensorProto, helper - from finn.core.datatype import DataType from finn.core.modelwrapper import ModelWrapper from finn.transformation.fpgadataflow.prepare_ip import PrepareIP -from finn.transformation.fpgadataflow.create_stitched_ip import CreateStitchedIP - +from finn.transformation.fpgadataflow.prepare_rtlsim import PrepareRTLSim from finn.transformation.fpgadataflow.hlssynth_ip import HLSSynthIP - from finn.transformation.fpgadataflow.set_exec_mode import SetExecMode from finn.transformation.general import GiveUniqueNodeNames - from finn.util.basic import gen_finn_dt_tensor - import finn.core.onnx_exec as oxe -from finn.transformation.fpgadataflow.insert_tlastmarker import InsertTLastMarker -from finn.transformation.fpgadataflow.make_deployment import DeployToPYNQ -from finn.transformation.fpgadataflow.prepare_rtlsim import PrepareRTLSim -from finn.transformation.fpgadataflow.make_pynq_driver import MakePYNQDriver -from finn.transformation.fpgadataflow.make_pynq_proj import MakePYNQProject -from finn.transformation.fpgadataflow.replace_verilog_relpaths import ( - ReplaceVerilogRelPaths, -) -from finn.transformation.fpgadataflow.synth_pynq_proj import SynthPYNQProject -from finn.util.basic import pynq_part_map -from finn.core.throughput_test import throughput_test_remote build_dir = "/tmp/" + os.environ["FINN_INST_NAME"] -test_pynq_board = os.getenv("PYNQ_BOARD", default="Pynq-Z1") -test_fpga_part = pynq_part_map[test_pynq_board] +test_fpga_part = "xc7z020clg400-1" target_clk_ns = 10 @@ -87,7 +70,6 @@ def test_fpgadataflow_fifo_rtlsim(Shape, folded_shape, depth, finn_dtype): model = make_single_fifo_modelwrapper(Shape, depth, folded_shape, finn_dtype) model = model.transform(SetExecMode("rtlsim")) - model = model.transform(InsertTLastMarker()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(PrepareIP(test_fpga_part, target_clk_ns)) model = model.transform(HLSSynthIP()) @@ -98,33 +80,3 @@ def test_fpgadataflow_fifo_rtlsim(Shape, folded_shape, depth, finn_dtype): ).all(), """The output values are not the same as the input values anymore.""" assert y.shape == tuple(Shape), """The output shape is incorrect.""" - - try: - ip = os.environ["PYNQ_IP"] # NOQA - if ip == "": - pytest.skip("PYNQ board IP address not specified") - model = model.transform(ReplaceVerilogRelPaths()) - model = model.transform(CreateStitchedIP(test_fpga_part, target_clk_ns)) - model = model.transform(MakePYNQProject(test_pynq_board)) - model = model.transform(SynthPYNQProject()) - model = model.transform(MakePYNQDriver(platform="zynq")) - username = os.getenv("PYNQ_USERNAME", "xilinx") - password = os.getenv("PYNQ_PASSWORD", "xilinx") - port = os.getenv("PYNQ_PORT", 22) - target_dir = os.getenv("PYNQ_TARGET_DIR", "/home/xilinx/finn") - model = model.transform(DeployToPYNQ(ip, port, username, password, target_dir)) - res = throughput_test_remote(model) - expected_dict = {} - expected_dict["runtime[ms]"] = [] - expected_dict["throughput[images/s]"] = [] - expected_dict["DRAM_in_bandwidth[Mb/s]"] = [] - expected_dict["DRAM_out_bandwidth[Mb/s]"] = [] - for key in expected_dict: - assert ( - key in res - ), """Throughput test not successful, no value for {} - in result dictionary""".format( - key - ) - except KeyError: - pytest.skip("PYNQ board IP address not specified") diff --git a/tests/fpgadataflow/test_fpgadataflow_ipstitch.py b/tests/fpgadataflow/test_fpgadataflow_ipstitch.py index 75a67f3508f1de69cebf466589d195a99f08dd94..fa7d59c2b607e80ec4c3ce0f2eb019ede8e50964 100644 --- a/tests/fpgadataflow/test_fpgadataflow_ipstitch.py +++ b/tests/fpgadataflow/test_fpgadataflow_ipstitch.py @@ -45,9 +45,6 @@ from finn.transformation.fpgadataflow.create_dataflow_partition import ( from finn.transformation.fpgadataflow.hlssynth_ip import HLSSynthIP from finn.transformation.fpgadataflow.insert_tlastmarker import InsertTLastMarker from finn.transformation.fpgadataflow.make_deployment import DeployToPYNQ -from finn.transformation.fpgadataflow.make_pynq_driver import MakePYNQDriver -from finn.transformation.fpgadataflow.make_pynq_proj import MakePYNQProject -from finn.transformation.fpgadataflow.synth_pynq_proj import SynthPYNQProject import finn.transformation.fpgadataflow.replace_verilog_relpaths as rvp from finn.transformation.general import GiveUniqueNodeNames from finn.util.basic import ( @@ -314,95 +311,6 @@ def test_fpgadataflow_ipstitch_synth_ooc(): assert ret["fmax_mhz"] > 100 -@pytest.mark.vivado -def test_fpgadataflow_ipstitch_pynq_projgen(): - model = load_test_checkpoint_or_skip( - ip_stitch_model_dir + "/test_fpgadataflow_ip_stitch.onnx" - ) - model = model.transform(MakePYNQProject(test_pynq_board)) - vivado_pynq_proj_dir = model.get_metadata_prop("vivado_pynq_proj") - assert vivado_pynq_proj_dir is not None - assert os.path.isdir(vivado_pynq_proj_dir) - model.save(ip_stitch_model_dir + "/test_fpgadataflow_pynq_projgen.onnx") - - -@pytest.mark.slow -@pytest.mark.vivado -def test_fpgadataflow_ipstitch_pynq_synth(): - model = load_test_checkpoint_or_skip( - ip_stitch_model_dir + "/test_fpgadataflow_pynq_projgen.onnx" - ) - model = model.transform(SynthPYNQProject()) - bitfile = model.get_metadata_prop("bitfile") - assert bitfile is not None - assert os.path.isfile(bitfile) - model.save(ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_synth.onnx") - - -def test_fpgadataflow_ipstitch_pynq_driver(): - model = load_test_checkpoint_or_skip( - ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_synth.onnx" - ) - model = model.transform(MakePYNQDriver(platform="zynq")) - driver_dir = model.get_metadata_prop("pynq_driver_dir") - assert driver_dir is not None - assert os.path.isdir(driver_dir) - model.save(ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_driver.onnx") - - -def test_fpgadataflow_ipstitch_pynq_deployment_folder(): - model = load_test_checkpoint_or_skip( - ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_driver.onnx" - ) - try: - ip = os.environ["PYNQ_IP"] # no default for this one; skip if not defined - if ip == "": - pytest.skip("PYNQ board IP address not specified") - username = os.getenv("PYNQ_USERNAME", "xilinx") - password = os.getenv("PYNQ_PASSWORD", "xilinx") - port = os.getenv("PYNQ_PORT", 22) - target_dir = os.getenv("PYNQ_TARGET_DIR", "/home/xilinx/finn") - model = model.transform(DeployToPYNQ(ip, port, username, password, target_dir)) - pynq_ip = model.get_metadata_prop("pynq_ip") - pynq_username = model.get_metadata_prop("pynq_username") - pynq_password = model.get_metadata_prop("pynq_password") - pynq_target_dir = model.get_metadata_prop("pynq_target_dir") - - assert pynq_ip == ip - assert pynq_username == username - assert pynq_password == password - assert pynq_target_dir == target_dir - - deployment_dir = model.get_metadata_prop("pynq_deploy_dir") - assert deployment_dir is not None - assert os.path.isdir(deployment_dir) - - model.save( - ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_deployment.onnx" - ) - except KeyError: - pytest.skip("PYNQ board IP address not specified") - - -def test_fpgadataflow_ipstitch_remote_execution(): - try: - ip = os.environ["PYNQ_IP"] # NOQA - if ip == "": - pytest.skip("PYNQ board IP address not specified") - model = load_test_checkpoint_or_skip( - ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_pynq_deployment.onnx" - ) - iname = "inp" - idt = model.get_tensor_datatype(iname) - ishape = model.get_tensor_shape(iname) - x = gen_finn_dt_tensor(idt, ishape) - input_dict = {"inp": x} - outp = execute_onnx(model, input_dict) - assert np.isclose(outp["outp"], x).all() - except KeyError: - pytest.skip("PYNQ board IP address not specified") - - def test_fpgadataflow_ipstitch_iodma_floorplan(): model = create_one_fc_model() if model.graph.node[0].op_type == "StreamingDataflowPartition": @@ -441,6 +349,9 @@ def test_fpgadataflow_ipstitch_vitis(board, period_ns, extw): model = load_test_checkpoint_or_skip(sdp_node.get_nodeattr("model")) model = model.transform(VitisBuild(fpga_part, period_ns, platform)) model.save(ip_stitch_model_dir + "/test_fpgadataflow_ipstitch_vitis.onnx") + assert model.get_metadata_prop("platform") == "alveo" + assert os.path.isdir(model.get_metadata_prop("vitis_link_proj")) + assert os.path.isfile(model.get_metadata_prop("bitfile")) # board diff --git a/tests/pynq/test_pynq_performance_end2end.py b/tests/pynq/test_pynq_performance_end2end.py deleted file mode 100644 index ea04ed9c402944730bf35374f46636ec433fe4c2..0000000000000000000000000000000000000000 --- a/tests/pynq/test_pynq_performance_end2end.py +++ /dev/null @@ -1,75 +0,0 @@ -import os - -import pytest -import numpy as np -from scipy.stats import linregress -import warnings -from finn.util.test import load_test_checkpoint_or_skip -from finn.core.throughput_test import throughput_test_remote - -build_dir = "/tmp/" + os.environ["FINN_INST_NAME"] - - -@pytest.mark.parametrize( - "end2end_example", - [ - "zynqbuild_tfc_w1a1", - "zynqbuild_cnv_w1a1", - "vitis_tfc_w1a1", - "tfc_w1a1", - "cnv_w1a1", - "cnv_w2a2", - ], -) -@pytest.mark.slow -def test_pynq_performance_end2end(end2end_example): - model = load_test_checkpoint_or_skip( - build_dir + "/end2end_%s_pynq_deploy.onnx" % end2end_example - ) - try: - ip = os.environ["PYNQ_IP"] # NOQA - board = os.environ["PYNQ_BOARD"] # NOQA - if ip == "" or board == "": - pytest.skip("PYNQ board or IP address not specified") - ret = dict() - # try a range of batch sizes, some may fail due to insufficient DMA - # buffers - bsize_range_in = [2 ** i for i in range(16)] - bsize_range = [] - for bsize in bsize_range_in: - res = throughput_test_remote(model, bsize) - if res is not None: - ret[bsize] = res - bsize_range.append(bsize) - else: - # assume we reached largest possible N - break - - y = [ret[key]["runtime[ms]"] for key in bsize_range] - lrret = linregress(bsize_range, y) - ret_str = "" - ret_str += "\n" + "%s Throughput Test Results" % end2end_example - ret_str += "\n" + "-----------------------------" - ret_str += "\n" + "From linear regression:" - ret_str += "\n" + "Invocation overhead: %f ms" % lrret.intercept - ret_str += "\n" + "Time per sample: %f ms" % lrret.slope - ret_str += "\n" + "Raw data:" - - ret_str += "\n" + "{:<8} {:<16} {:<16} {:<16} {:<16} {:<16}".format( - "N", "runtime[ms]", "fclk[mhz]", "fps", "DRAM rd[Mb/s]", "DRAM wr[Mb/s]" - ) - for k in bsize_range: - v = ret[k] - ret_str += "\n" + "{:<8} {:<16} {:<16} {:<16} {:<16} {:<16}".format( - k, - np.round(v["runtime[ms]"], 4), - v["fclk[mhz]"], - np.round(v["throughput[images/s]"], 2), - np.round(v["DRAM_in_bandwidth[Mb/s]"], 2), - np.round(v["DRAM_out_bandwidth[Mb/s]"], 2), - ) - ret_str += "\n" + "-----------------------------" - warnings.warn(ret_str) - - except KeyError: - pytest.skip("PYNQ board or IP address not specified") diff --git a/tests/pynq/test_pynq_performance_fifo.py b/tests/pynq/test_pynq_performance_fifo.py deleted file mode 100644 index b1f69527d98694b325f910cdffd21c3914aeff7e..0000000000000000000000000000000000000000 --- a/tests/pynq/test_pynq_performance_fifo.py +++ /dev/null @@ -1,128 +0,0 @@ -import os - -import pytest - -import numpy as np -from onnx import TensorProto, helper - -from finn.core.datatype import DataType -from finn.core.modelwrapper import ModelWrapper -from finn.transformation.fpgadataflow.prepare_ip import PrepareIP -from finn.transformation.fpgadataflow.create_stitched_ip import CreateStitchedIP -from finn.transformation.fpgadataflow.hlssynth_ip import HLSSynthIP -from finn.transformation.fpgadataflow.insert_tlastmarker import InsertTLastMarker -from finn.transformation.fpgadataflow.make_deployment import DeployToPYNQ -from finn.transformation.fpgadataflow.make_pynq_driver import MakePYNQDriver -from finn.transformation.fpgadataflow.make_pynq_proj import MakePYNQProject -from finn.transformation.fpgadataflow.synth_pynq_proj import SynthPYNQProject -import finn.transformation.fpgadataflow.replace_verilog_relpaths as rvp -from finn.transformation.general import GiveUniqueNodeNames -from finn.util.basic import pynq_part_map, pynq_native_port_width -from finn.core.throughput_test import throughput_test_remote -from scipy.stats import linregress -import warnings - - -def make_single_fifo_modelwrapper(Shape, Depth, fld_shape, finn_dtype): - - inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, Shape) - outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, Shape) - - FIFO_node = helper.make_node( - "StreamingFIFO", - ["inp"], - ["outp"], - domain="finn", - backend="fpgadataflow", - depth=Depth, - folded_shape=fld_shape, - dataType=str(finn_dtype.name), - ) - - graph = helper.make_graph( - nodes=[FIFO_node], name="fifo_graph", inputs=[inp], outputs=[outp] - ) - - model = helper.make_model(graph, producer_name="fifo-model") - model = ModelWrapper(model) - - model.set_tensor_datatype("inp", finn_dtype) - model.set_tensor_datatype("outp", finn_dtype) - - return model - - -@pytest.mark.vivado -@pytest.mark.slow -def test_pynq_performance_fifo(): - try: - ip = os.environ["PYNQ_IP"] # NOQA - board = os.environ["PYNQ_BOARD"] # NOQA - if ip == "" or board == "": - pytest.skip("PYNQ board or IP address not specified") - fifo_width = pynq_native_port_width[board] - shape = (1, fifo_width) - folded_shape = (1, 1, fifo_width) - depth = 16 - clk_ns = 10 - dtype = DataType.BIPOLAR - fpga_part = pynq_part_map[board] - username = os.getenv("PYNQ_USERNAME", "xilinx") - password = os.getenv("PYNQ_PASSWORD", "xilinx") - port = os.getenv("PYNQ_PORT", 22) - target_dir = os.getenv("PYNQ_TARGET_DIR", "/home/xilinx/finn") - - model = make_single_fifo_modelwrapper(shape, depth, folded_shape, dtype) - model = model.transform(InsertTLastMarker()) - model = model.transform(GiveUniqueNodeNames()) - model = model.transform(PrepareIP(fpga_part, clk_ns)) - model = model.transform(HLSSynthIP()) - model = model.transform(rvp.ReplaceVerilogRelPaths()) - model = model.transform(CreateStitchedIP(fpga_part, clk_ns)) - model = model.transform(MakePYNQProject(board)) - model = model.transform(SynthPYNQProject()) - model = model.transform(MakePYNQDriver(platform="zynq")) - model = model.transform(DeployToPYNQ(ip, port, username, password, target_dir)) - - ret = dict() - # try a range of batch sizes, some may fail due to insufficient DMA - # buffers - bsize_range_in = [2 ** i for i in range(20)] - bsize_range = [] - for bsize in bsize_range_in: - res = throughput_test_remote(model, bsize) - if res is not None: - ret[bsize] = res - bsize_range.append(bsize) - else: - # assume we reached largest possible N - break - - y = [ret[key]["runtime[ms]"] for key in bsize_range] - lrret = linregress(bsize_range, y) - ret_str = "" - ret_str += "\n" + "FIFO Throughput Test Results" - ret_str += "\n" + "-----------------------------" - ret_str += "\n" + "From linear regression:" - ret_str += "\n" + "Invocation overhead: %f ms" % lrret.intercept - ret_str += "\n" + "Time per sample: %f ms" % lrret.slope - ret_str += "\n" + "Raw data:" - - ret_str += "\n" + "{:<8} {:<16} {:<16} {:<16} {:<16} {:<16}".format( - "N", "runtime[ms]", "fclk[mhz]", "fps", "DRAM rd[Mb/s]", "DRAM wr[Mb/s]" - ) - for k in bsize_range: - v = ret[k] - ret_str += "\n" + "{:<8} {:<16} {:<16} {:<16} {:<16} {:<16}".format( - k, - np.round(v["runtime[ms]"], 4), - v["fclk[mhz]"], - np.round(v["throughput[images/s]"], 2), - np.round(v["DRAM_in_bandwidth[Mb/s]"], 2), - np.round(v["DRAM_out_bandwidth[Mb/s]"], 2), - ) - ret_str += "\n" + "-----------------------------" - warnings.warn(ret_str) - - except KeyError: - pytest.skip("PYNQ board or IP address not specified")