Skip to content

Commit

Permalink
PL Server now uses global state file (based on PYNQ-Metadata) rather …
Browse files Browse the repository at this point in the history
…than separate process.

* Improves performance when accessing non-dereferenced IP from dictionaries, such as DMA.

* Instead of a separate process that can be queried for information of dictionaries etc.. a PYNQ-Metadata json
file is stored globally that is only referenced when an overlay is downloaded. This file can be parsed on overlay
download to check for AXI Shutdown IP that needs to be triggered.

* PL.py now uses the global state file to access the currently loaded dictionaries outside the process that
configured the overlay.

* Bugfix for buffers where they are now freed when deleted/go out of scope.
  • Loading branch information
STFleming authored and skalade committed Sep 28, 2022
1 parent 3dbbc84 commit 2c83310
Show file tree
Hide file tree
Showing 13 changed files with 939 additions and 1,597 deletions.
134 changes: 84 additions & 50 deletions pynq/pl.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,23 @@
# Copyright (c) 2016, Xilinx, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder 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.
# SPDX-License-Identifier: BSD-3-Clause

import os
import struct
import warnings
from copy import deepcopy
from datetime import datetime
import struct
from multiprocessing.connection import Client, Listener
from pathlib import Path

import numpy as np
from multiprocessing.connection import Listener
from multiprocessing.connection import Client
from .mmio import MMIO
from .ps import CPU_ARCH_IS_SUPPORTED, CPU_ARCH, ZYNQ_ARCH, ZU_ARCH
from .devicetree import DeviceTreeSegment
from .devicetree import get_dtbo_path
from .devicetree import get_dtbo_base_name

from .pl_server import HWH
from .pl_server import get_hwh_name
from .pl_server import Device
from .devicetree import DeviceTreeSegment, get_dtbo_base_name, get_dtbo_path
from .mmio import MMIO
from .pl_server.device import Device
from .pl_server.global_state import clear_global_state, load_global_state, global_state_file_exists
from .pl_server.hwh_parser import HWH, get_hwh_name
from .ps import CPU_ARCH, CPU_ARCH_IS_SUPPORTED, ZU_ARCH, ZYNQ_ARCH

__author__ = "Yun Rock Qu"
__copyright__ = "Copyright 2016, Xilinx"
__email__ = "[email protected]"


class PLMeta(type):
Expand Down Expand Up @@ -77,7 +47,13 @@ def bitfile_name(cls):
The absolute path of the bitstream currently on PL.
"""
return Device.active_device.bitfile_name
if hasattr(Device.active_device, "bitfile_name"):
if not Device.active_device.bitfile_name is None:
return Device.active_device.bitfile_name

if global_state_file_exists():
gs = load_global_state()
return gs.bitfile_name

@property
def timestamp(cls):
Expand All @@ -91,6 +67,27 @@ def timestamp(cls):
"""
return Device.active_device.timestamp

@property
def dict_views(cls):
"""
Getter attribute for the `systemgraph`
First checks to see if the metadata file is where it is expected.
If it is, parses it, and create a runtime_views object for it
"""
if hasattr(cls, "_dict_views_cached"):
return cls._dict_view_cache
else:
import os
from pynqmetadata.frontends import Metadata
from .metadata.runtime_metadata_parser import RuntimeMetadataParser
metadata_state_file = Path(f"{os.path.dirname(__file__)}/pl_server/_current_metadata.json")
if os.path.isfile(metadata_state_file):
cls._dict_views_cached = True
cls._dict_view_cache = RuntimeMetadataParser(Metadata(input=metadata_state_file))
return cls._dict_view_cache
else:
return None

@property
def ip_dict(cls):
"""The getter for the attribute `ip_dict`.
Expand All @@ -101,7 +98,12 @@ def ip_dict(cls):
The dictionary storing addressable IP instances; can be empty.
"""
return Device.active_device.ip_dict
if hasattr(Device.active_device, "ip_dict"):
if not Device.active_device.ip_dict is None:
return Device.active_device.ip_dict

if not cls.dict_views is None:
return cls.dict_views.ip_dict

@property
def gpio_dict(cls):
Expand All @@ -113,7 +115,12 @@ def gpio_dict(cls):
The dictionary storing the PS GPIO pins.
"""
return Device.active_device.gpio_dict
if hasattr(Device.active_device, "gpio_dict"):
if not Device.active_device.gpio_dict is None:
return Device.active_device.gpio_dict

if not cls.dict_views is None:
return cls.dict_views.gpio_dict

@property
def interrupt_controllers(cls):
Expand All @@ -125,7 +132,12 @@ def interrupt_controllers(cls):
The dictionary storing interrupt controller information.
"""
return Device.active_device.interrupt_controllers
if hasattr(Device.active_device, "interrupt_controllers"):
if not Device.active_device.interrupt_controllers is None:
return Device.active_device.interrupt_controllers

if not cls.dict_views is None:
return cls.dict_views.interrupt_controllers

@property
def interrupt_pins(cls):
Expand All @@ -137,7 +149,12 @@ def interrupt_pins(cls):
The dictionary storing the interrupt endpoint information.
"""
return Device.active_device.interrupt_pins
if hasattr(Device.active_device, "interrupt_pins"):
if not Device.active_device.interrupt_pins is None:
return Device.active_device.interrupt_pins

if not cls.dict_views is None:
return cls.dict_views.interrupt_pins

@property
def hierarchy_dict(cls):
Expand All @@ -149,7 +166,12 @@ def hierarchy_dict(cls):
The dictionary containing the hierarchies in the design
"""
return Device.active_device.hierarchy_dict
if hasattr(Device.active_device, "hierarchy_dict"):
if not Device.active_device.hierarchy_dict is None:
return Device.active_device.hierarchy_dict

if not cls.dict_views.hierarchy_dict is None:
return cls.dict_views.hierarchy_dict

@property
def devicetree_dict(cls):
Expand Down Expand Up @@ -185,7 +207,12 @@ def mem_dict(self):
The dictionary containing the memories in the design.
"""
return Device.active_device.mem_dict
if hasattr(Device.active_device, "mem_dict"):
if not Device.active_device.mem_dict is None:
return Device.active_device.mem_dict

if not self.dict_views.mem_dict is None:
return self.dict_views.mem_dict

def shutdown(cls):
"""Shutdown the AXI connections to the PL in preparation for
Expand Down Expand Up @@ -213,7 +240,11 @@ def reset(cls, parser=None):
A parser object to speed up the reset process.
"""
Device.active_device.reset(parser)
clear_global_state()
for i in cls.mem_dict.values():
i['state'] = None
for i in cls.ip_dict.values():
i['state'] = None

def clear_dict(cls):
"""Clear all the dictionaries stored in PL.
Expand Down Expand Up @@ -350,6 +381,7 @@ class PL(metaclass=PLMeta):
'gpio': dict, 'fullpath': str}}
"""

def __init__(self):
"""Return a new PL object.
Expand All @@ -358,4 +390,6 @@ def __init__(self):
"""
euid = os.geteuid()
if euid != 0:
raise EnvironmentError('Root permissions required.')
raise EnvironmentError("Root permissions required.")


49 changes: 14 additions & 35 deletions pynq/pl_server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,22 @@
# Copyright (c) 2016, Xilinx, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder 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.
# SPDX-License-Identifier: BSD-3-Clause

__author__ = "Peter Ogden"
__copyright__ = "Copyright 2019, Xilinx"
__email__ = "[email protected]"


from .hwh_parser import HWH, get_hwh_name
from .server import DeviceClient
import os

from .device import Device
from .global_state import (
GlobalState,
global_state_file_exists,
load_global_state,
save_global_state,
)
from .hwh_parser import HWH, get_hwh_name

import os
if 'XILINX_XRT' in os.environ:
if "XILINX_XRT" in os.environ:
from .embedded_device import EmbeddedDevice
from .xclbin_parser import XclBin
from .xrt_device import XrtDevice
from .embedded_device import EmbeddedDevice


Loading

0 comments on commit 2c83310

Please sign in to comment.