diff options
author | Kshitij Sisodia <kshitij.sisodia@arm.com> | 2022-09-30 16:42:50 +0100 |
---|---|---|
committer | Kristofer Jonsson <kristofer.jonsson@arm.com> | 2022-10-25 16:36:45 +0000 |
commit | f9efe0ddf865c55d28bcaa203fefffa94bf09b42 (patch) | |
tree | 928da5f68dafd7e5a0dee05a75f2f6fcd52df170 /driver_library/python/src | |
parent | 569aa558f5e7638852a928feede1f21e7323f664 (diff) | |
download | ethos-u-linux-driver-stack-f9efe0ddf865c55d28bcaa203fefffa94bf09b42.tar.gz |
Added Python interface for Arm Ethos-U NPU driver library.22.11-rc1
Python `ethosu_driver` could be built as part of Arm Ethos-U Linux
driver library CMake flow.
See driver_library/python/README.md for more details.
Change-Id: I177a890add5c13df9a839f4f43621f972afe5ab1
Signed-off-by: Kshitij Sisodia <kshitij.sisodia@arm.com>
Diffstat (limited to 'driver_library/python/src')
8 files changed, 945 insertions, 0 deletions
diff --git a/driver_library/python/src/ethosu_driver/__init__.py b/driver_library/python/src/ethosu_driver/__init__.py new file mode 100644 index 0000000..ee6ea1f --- /dev/null +++ b/driver_library/python/src/ethosu_driver/__init__.py @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +# SPDX-License-Identifier: Apache-2.0 + +from ._generated.driver import Device, Inference, Network, Buffer +from ._utilities import open_device, load_model, populate_buffers, \ + allocate_buffers, get_results, InferenceRunner diff --git a/driver_library/python/src/ethosu_driver/_generated/__init__.py b/driver_library/python/src/ethosu_driver/_generated/__init__.py new file mode 100644 index 0000000..6a36657 --- /dev/null +++ b/driver_library/python/src/ethosu_driver/_generated/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +# SPDX-License-Identifier: Apache-2.0 diff --git a/driver_library/python/src/ethosu_driver/_utilities/__init__.py b/driver_library/python/src/ethosu_driver/_utilities/__init__.py new file mode 100644 index 0000000..c0dc1eb --- /dev/null +++ b/driver_library/python/src/ethosu_driver/_utilities/__init__.py @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +# SPDX-License-Identifier: Apache-2.0 + +from .driver_utilities import open_device, load_model, populate_buffers, \ + allocate_buffers, get_results, InferenceRunner diff --git a/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py b/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py new file mode 100644 index 0000000..216895a --- /dev/null +++ b/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py @@ -0,0 +1,186 @@ +# SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +# SPDX-License-Identifier: Apache-2.0 +import logging +import time +from typing import List +from .._generated.driver import Device, Inference, Network, Buffer, InferenceStatus_OK + + +def open_device(device: str) -> Device: + """Opens the Ethos-U device file descriptor. + + Args: + device: device name. + + Returns: + `Device`: Return the object that represents Ethos-U device file descriptor and manages Ethos-U device lifecycle. + """ + device = Device("/dev/{}".format(device)) + return device + + +def load_model(device: Device, model: str) -> Network: + """Create a `Network` when providing `Device` object and a string containing tflite file path. + + Args: + device: `Device` object that Ethos-U device file descriptor. + model: tflite model file path . + + Returns: + `Network`: Return the object that represent the neural __network file descriptor received from the Ethos-U device. + """ + logging.info("Creating network") + network_buffer = Buffer(device, model) + return Network(device, network_buffer) + + +def populate_buffers(input_data: List[bytearray], buffers: List[Buffer]): + """Set the feature maps associated memory buffer with the given data. + + Args: + input_data: list of input feature maps data. + buffers: list of already initialized ifm buffers. + Raises: + RuntimeError: if input data size is incorrect. + """ + number_of_buffers = len(buffers) + + if number_of_buffers != len(input_data): + raise RuntimeError("Incorrect number of inputs, expected {}, got {}.".format(number_of_buffers, len(input_data))) + + for index, (buffer, data_chunk) in enumerate(zip(buffers, input_data)): + cap = buffer.capacity() + logging.info("Copying data to a buffer {} of {} with size = {}".format(index + 1, number_of_buffers, cap)) + + if len(data_chunk) > cap: + raise RuntimeError("Buffer expects {} bytes, got {} bytes.".format(cap, len(data_chunk))) + buffer.resize(len(data_chunk)) + buffer.from_buffer(data_chunk) + + +def allocate_buffers(device: Device, dimensions: List) -> List[Buffer]: + """Returns output feature maps associated with memory buffers. + + Args: + device: `Device` object that Ethos-U device file descriptor. + dimensions: `Network` object that represent the neural __network file descriptor. + + Returns: + list: output feature map buffers. + """ + buffers = [] + total = len(dimensions) + for index, size in enumerate(dimensions): + logging.info("Allocating {} of {} buffer with size = {}".format(index + 1, total, size)) + buffer = Buffer(device, size) + buffers.append(buffer) + + return buffers + + +def get_results(inference: Inference) -> List[Buffer]: + """Retrieves output inference buffers + + Args: + inference: `Inference` object that represents the inference file descriptor. + + Returns: + list: list of buffer objects + Raises: + RuntimeError: in case of inference returned failure status. + + """ + if InferenceStatus_OK != inference.status(): + raise RuntimeError("Inference failed!") + else: + logging.info("Inference succeeded!") + return inference.getOfmBuffers() + + +class InferenceRunner: + """Helper class to execute inference.""" + + def __init__(self, device_name: str, model: str): + """Initialises instance to execute inferences on the given model with given device + + Device is opened with the name '/dev/<device_name>'. + Input/Output feature maps memory is allocated. + + Args: + device_name: npu device name + model: Tflite model file path + """ + self.__device = open_device(device_name) + if not InferenceRunner.wait_for_ping(self.__device, 3): + raise RuntimeError("Failed to communicate with device {}".format(device_name)) + + self.__network = load_model(self.__device, model) + # it is important to have a reference to current inference object to have access to OFMs. + self.__inf = None + self.__enabled_counters = () + + @staticmethod + def wait_for_ping(device: Device, count: int) -> bool: + if count == 0: + return False + try: + device.ping() + return True + except: + logging.info("Waiting for device: {}".format(count)) + time.sleep(0.5) + return InferenceRunner.wait_for_ping(device, count-1) + + def set_enabled_counters(self, enabled_counters: List[int] = ()): + """Set the enabled performance counter to use during inference. + + Args: + enabled_counters: list of integer counter to enable. + Raises: + ValueError: in case of inference returned failure status or the Pmu counter requests exceed the maximum supported. + """ + max_pmu_events = Inference.getMaxPmuEventCounters() + if len(enabled_counters) > max_pmu_events: + raise ValueError("Number of PMU counters requested exceed the maximum supported ({}).".format(max_pmu_events)) + self.__enabled_counters = enabled_counters + + def run(self, input_data: List[bytearray], timeout: int) -> List[Buffer]: + """Run a inference with the given input feature maps data. + + Args: + input_data: data list containing input data as binary arrays + timeout: inference timout in nano seconds + + Returns: + list: list of buffer objects + """ + ofms = allocate_buffers(self.__device, self.__network.getOfmDims()) + ifms = allocate_buffers(self.__device, self.__network.getIfmDims()) + populate_buffers(input_data, ifms) + + self.__inf = Inference( + self.__network, + ifms, + ofms, + self.__enabled_counters, + True) + + self.__inf.wait(int(timeout)) + return get_results(self.__inf) + + def get_pmu_counters(self) -> List: + """Return the PMU data for the inference run. + + Returns: + list: pairs of PMU type and cycle count value + """ + return list(zip(self.__enabled_counters, self.__inf.getPmuCounters())) + + def get_pmu_total_cycles(self) -> int: + """ + Returns the total cycle count, including idle cycles, as reported by + the PMU + + Returns: total cycle count + """ + return self.__inf.getCycleCounter() diff --git a/driver_library/python/src/ethosu_driver/inference_runner.py b/driver_library/python/src/ethosu_driver/inference_runner.py new file mode 100644 index 0000000..1998465 --- /dev/null +++ b/driver_library/python/src/ethosu_driver/inference_runner.py @@ -0,0 +1,100 @@ +# +# SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +# SPDX-License-Identifier: Apache-2.0 +# +from argparse import ArgumentParser +import os +import logging +from pathlib import Path +from typing import List + +import ethosu_driver as driver +try: + import numpy as np + with_numpy = True +except ImportError: + with_numpy = False + + +def read_bin_file_to_buf(file_path: str) -> bytearray: + with open(file_path, 'rb') as f: + return bytearray(f.read()) + + +def read_npy_file_to_buf(file_path: str) -> bytearray: + ifm_arr = np.load(file_path).astype(dtype=np.int8, order='C') + return ifm_arr.flatten().data + + +def read_ifms(ifm_files: List[str], use_npy: bool = False): + read_file_to_buf = read_npy_file_to_buf if use_npy else read_bin_file_to_buf + for ifm_file in ifm_files: + yield read_file_to_buf(ifm_file) + + +def write_npy(dir: str, file_name: str, data: memoryview): + ar = np.frombuffer(data, dtype=np.int8) + file_path = os.path.join(dir, "{}.npy".format(file_name)) + if os.path.isfile(file_path): + os.remove(file_path) + np.save(file_path, ar) + logging.info("File saved to {}".format(file_path)) + + +def write_bin_file(dir: str, file_name: str, data: memoryview): + file_path = os.path.join(dir, "{}.bin".format(file_name)) + if os.path.isfile(file_path): + os.remove(file_path) + with open(file_path, "wb") as f: + f.write(data) + logging.info("File saved to {}".format(file_path)) + + +def write_ofm(buf: memoryview, ofm_index: int, model_path: str, output_dir: str, use_npy: bool = False): + write_buf_to_file = write_npy if use_npy else write_bin_file + model_file_name = Path(model_path).name + ofm_name = "{}_ofm_{}".format(model_file_name, ofm_index) + write_buf_to_file(output_dir, ofm_name, buf) + + +def main(): + format = "%(asctime)s %(levelname)s - %(message)s" + logging.basicConfig(format=format, level=logging.INFO) + + parser = ArgumentParser() + parser.add_argument("--device", help="Npu device name. Default: ethosu0", default="ethosu0") + parser.add_argument("--model", help="Tflite model file path", required=True) + parser.add_argument("--timeout", help="Inference timout in seconds, Default: infinite", default=-1, type=int) + parser.add_argument("--inputs", nargs='+', help="list of files containing input feature maps", required=True) + parser.add_argument("--output_dir", help="directory to store inference results, output feature maps. " + "Default: current directory", default=os.getcwd()) + parser.add_argument("--npy", help="Use npy input/output", default=0, type=int) + parser.add_argument("--profile_counters", help="Performance counters to profile", nargs=4, type=int, required=True) + args = parser.parse_args() + + use_numpy = with_numpy & bool(int(args.npy)) + if use_numpy: + logging.info("Running with numpy inputs/outputs") + else: + logging.info("Running with byte array inputs/outputs") + + # @TODO: Discuss if this is needed anymore. Remove this commented line, if not. + # driver.reset() + + ifms_data = read_ifms(args.inputs, use_numpy) + + runner = driver.InferenceRunner(args.device, args.model) + runner.set_enabled_counters(args.profile_counters) + ofm_buffers = runner.run(list(ifms_data), int(args.timeout)) + + for index, buffer_out in enumerate(ofm_buffers): + logging.info("Output buffer size: {}".format(buffer_out.size())) + write_ofm(buffer_out.data(), index, args.model, args.output_dir, use_numpy) + + inference_pmu_counters = runner.get_pmu_counters() + + # Profiling + total_cycles = runner.get_pmu_total_cycles() + for pmu, value in inference_pmu_counters: + logging.info("\tNPU %d counter: %d", pmu, value) + logging.info("\tNPU TOTAL cycles: %d", total_cycles) diff --git a/driver_library/python/src/ethosu_driver/swig/driver.i b/driver_library/python/src/ethosu_driver/swig/driver.i new file mode 100644 index 0000000..4cd8bdf --- /dev/null +++ b/driver_library/python/src/ethosu_driver/swig/driver.i @@ -0,0 +1,554 @@ +// +// SPDX-FileCopyrightText: Copyright 2020, 2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +// SPDX-License-Identifier: Apache-2.0 +// +%module driver +%{ +#define SWIG_FILE_WITH_INIT +%} + +//typemap definitions and other common stuff +%include "standard_header.i" + +%{ +#include "ethosu.hpp" +#include <fstream> +#include <list> +#include <string> +#include <cstring> +#include <sstream> +#include <linux/ioctl.h> + +#define ETHOSU_IOCTL_BASE 0x01 +#define ETHOSU_IO(nr) _IO(ETHOSU_IOCTL_BASE, nr) +#define ETHOSU_IOCTL_PING ETHOSU_IO(0x00) + +%} +%include <typemaps/buffer.i> + +%shared_ptr(EthosU::Buffer); +%shared_ptr(EthosU::Network); + + +namespace std { + %template(UintVector) vector<unsigned int>; + %template(SizeTVector) vector<size_t>; + %template(SharedBufferVector) vector<shared_ptr<EthosU::Buffer>>; +} + +namespace EthosU +{ + +%feature("docstring", +" +Semantic Version : major.minor.patch +") SemanticVersion; +%nodefaultctor SemanticVersion; +class SemanticVersion { +public: + SemanticVersion(uint32_t major = 0, uint32_t minor = 0, uint32_t patch = 0); + + uint32_t major; + uint32_t minor; + uint32_t patch; +}; + +%extend SemanticVersion { + std::string __str__() const { + std::ostringstream out; + out << *$self; + return out.str(); + } +} + +%feature("docstring", +" +Hardware Identifier which consists of version status, version revision, product revision and architecture revision. +") HardwareId; +class HardwareId { +public: + HardwareId(uint32_t versionStatus, SemanticVersion& version, SemanticVersion& product, SemanticVersion& arch); + + uint32_t versionStatus{0}; + SemanticVersion version{}; + SemanticVersion product{}; + SemanticVersion architecture{}; +}; + +%extend HardwareId { + std::string __str__() const { + std::ostringstream out; + out << "{versionStatus=" << $self->versionStatus << + ", version=" << EthosU_SemanticVersion___str__(&$self->version) << + ", product=" << EthosU_SemanticVersion___str__(&$self->product) << + ", architecture=" << EthosU_SemanticVersion___str__(&$self->architecture) << "}"; + return out.str(); + } +} + +%feature("docstring", +" +Hardware Configuration object defines specific configuration including MACs per clock cycle and NPU command stream +version. This also specifies is custom DMA is enabled or not. +") HardwareConfiguration; +%nodefaultctor HardwareConfiguration; +class HardwareConfiguration { + public: + HardwareConfiguration(uint32_t macs = 0, uint32_t cmdStreamVersion = 0, bool customDma = false); + + uint32_t macsPerClockCycle; + uint32_t cmdStreamVersion; + bool customDma; +}; + +%extend HardwareConfiguration { + std::string __str__() const { + std::ostringstream out; + out << "{macsPerClockCycle=" << $self->macsPerClockCycle << + ", cmdStreamVersion=" << $self->cmdStreamVersion << + ", customDma=" << ($self->customDma? "True": "False") << "}"; + return out.str(); + } +} + +%feature("docstring", +" +Device capabilities object which specifies capabilities based on hardware ID, configuration and semantic version. +") Capabilities; +class Capabilities { + public: + Capabilities() {} + Capabilities(const HardwareId& hwId, const HardwareConfiguration& hwCfg, const SemanticVersion& driverVersion); + + HardwareId hwId; + HardwareConfiguration hwCfg; + SemanticVersion driver; +}; + +%extend Capabilities { + std::string __str__() const { + std::ostringstream out; + out << "{hwId=" << EthosU_HardwareId___str__(&$self->hwId) << + ", hwCfg=" << EthosU_HardwareConfiguration___str__(&$self->hwCfg) << + ", driver=" << EthosU_SemanticVersion___str__(&$self->driver) << "}"; + return out.str(); + } +} + +%feature("docstring", +" +Device object represents Ethos-U device file descriptor and manages Ethos-U device lifecycle. +Constructor accepts device name and opens file descriptor with O_RDWR | O_NONBLOCK flags. +When the object is destroyed - device file descriptor is closed. +") Device; +%nodefaultctor Device; +class Device { +public: + Device(const char *device); + + %feature("docstring", + " + Performs the I/O control operation on the Ethos-U device. + + Args: + cmd: Command code + data: Command data + Returns: + int: Return value depends on command. Usually -1 indicates error. + ") ioctl; + int ioctl(unsigned long cmd, void *data = nullptr) const; + + %feature("docstring", + " + Returns the capabilities of the Ethos-U device. + + Returns: + Capabilities: Return capabilities of device. + ") capabilities; + Capabilities capabilities() const; +}; + +%extend Device { + + %feature("docstring", + " + Sends ping command to the Ethos-U device. + + See ETHOSU_IOCTL_PING from kernel module uapi/ethosu.h + ") ping; + void ping() { + $self->ioctl(ETHOSU_IOCTL_PING); + } +} + +%feature("docstring", + " + Buffer object represents a RW mapping in the virtual address space of the caller. + + Created mapping is shareable, updates to the mapping are visible to other processes mapping the same region. + Issues ETHOSU_IOCTL_BUFFER_CREATE I/O request to the device with given Maximum capacity. + + Buffer could be created for a device with given maximum capacity or instantiated directly from + a file containing binary data. + + Examples: + >>> import ethosu_driver as driver + >>> # from file: + >>> buf = driver.Buffer(device, '/path/to/file') + >>> # Empty, with maximum capacity: + >>> buf = driver.Buffer(device, 1024) + ") Buffer; +%nodefaultctor Buffer; +class Buffer { +public: + Buffer(const Device &device, const size_t capacity); + + %feature("docstring", + " + Returns maximum buffer capacity set during initialisation. + + Returns: + int: maximum buffer capacity. + ") capacity; + size_t capacity() const; + + %feature("docstring", + " + Sets the size of the device buffer to 0. + ") clear; + void clear() const; + + %feature("docstring", + " + Returns a readonly view to the mapped memory. + + Returns: + memoryview: readonly memory data. + ") data; + %driver_buffer_out; + char* data() const; + %clear_driver_buffer_out; + + %feature("docstring", + " + Sets a size of the memory buffer for the device. + + 'offset + size' must not exceed the capacity of the buffer. + Does not change the size of the mapped region. + + Issues ETHOSU_IOCTL_BUFFER_SET I/O request with a given size and offset. + + Args: + size (int): Device buffer size. + offset (int): Offset to where the data starts. + ") resize; + void resize(size_t size, size_t offset = 0) const; + + %feature("docstring", + " + Queries device and returns buffer data offset. + + Issues ETHOSU_IOCTL_BUFFER_GET I/O request. + + Returns: + int: data offset + ") offset; + size_t offset() const; + + %feature("docstring", + " + Queries device and returns buffer data size. + + Issues ETHOSU_IOCTL_BUFFER_GET I/O request. + + Returns: + int: current device buffer size. + ") size; + size_t size() const; + + %feature("docstring", + " + Returns buffer file descriptor id. + + Returns: + int: file descriptor id. + ") getFd; + int getFd() const; +}; + +%extend Buffer { + + Buffer(const Device& device, const std::string& filename) { + std::ifstream stream(filename, std::ios::binary); + if (!stream.is_open()) { + throw EthosU::Exception(std::string("Failed to open file: ").append(filename).c_str()); + } + + stream.seekg(0, std::ios_base::end); + size_t size = stream.tellg(); + stream.seekg(0, std::ios_base::beg); + + auto buffer = new EthosU::Buffer(device, size); + buffer->resize(size); + stream.read(buffer->data(), size); + + return buffer; + } + + %feature("docstring", + " + Fills the buffer from python buffer. + + Copies python buffer data to the mapped memory region. + Input buffer size must be within `Buffer` maximum capacity. + + Args: + buffer: data to be copied to the mapped memory. + + ") from_buffer; + %mutable_buffer(char* buffer, size_t size); + void from_buffer(char* buffer, size_t size) { + self->resize(size); + char* data = $self->data(); + std::memcpy(data, buffer, size); + } + %clear_mutable_buffer(char* buffer, size_t size); +} + +%feature("docstring", + " + Represents the neural network file descriptor received from the Ethos-U device. + + `Network` is created providing `Device` object and a `Buffer` containing tflite file data. + Network creation issues ETHOSU_IOCTL_NETWORK_CREATE I/O request with buffer file descriptor id. + Provided `Buffer` data is parsed into tflite Model object and input/output feature maps sizes are saved. + + Destruction of the object closes network file descriptor. + ") Network; +%nodefaultctor Network; +class Network { +public: + + %feature("docstring", + " + Performs the I/O control operation with network buffer device. + + Args: + cmd: Command code + data: Command data + Returns: + int: Return value depends on command. Usually -1 indicates error. + ") ioctl; + int ioctl(unsigned long cmd, void *data); + + %feature("docstring", + " + Returns associated memory buffer. + + Returns: + `Buffer`: buffer object used during initialisation. + ") getBuffer; + std::shared_ptr<Buffer> getBuffer(); + + %feature("docstring", + " + Returns saved sizes of the neural network model input feature maps. + + Returns: + list: sizes of all input feature maps + ") getIfmDims; + const std::vector<size_t> &getIfmDims() const; + + %feature("docstring", + " + Returns total size of all input feature maps. + + Returns: + int: total size of all input feature maps + ") getIfmSize; + size_t getIfmSize() const; + + %feature("docstring", + " + Returns saved sizes of the neural network model output feature maps. + + Returns: + list: sizes of all output feature maps + ") getOfmDims; + const std::vector<size_t> &getOfmDims() const; + + %feature("docstring", + " + Returns total size of all output feature maps. + + Returns: + int: total size of all output feature maps + ") getOfmSize; + size_t getOfmSize() const; +}; + +%extend Network { + Network(const Device &device, std::shared_ptr<Buffer> &buffer) + { + if(buffer == nullptr){ + throw EthosU::Exception(std::string("Failed to create the network, buffer is nullptr.").c_str()); + } + auto network = new EthosU::Network(device, buffer); + return network; + } +} + +%extend Network { + Network(const Device &device, const unsigned int index) + { + auto network = new EthosU::Network(device, index); + return network; + } +} + +%feature("docstring", + " + InferenceStatus enumeration + ") InferenceStatus; +enum class InferenceStatus { + OK, + ERROR, + RUNNING, + REJECTED, + ABORTED, + ABORTING + }; + +%feature("docstring", + " + Represents the inference file descriptor received from the Ethos-U device. + + `Inference` is created providing `Network` object and lists of input and output feature maps buffers. + Feature map buffers are copied. + + Inference creation issues ETHOSU_IOCTL_INFERENCE_CREATE I/O request with + file descriptor ids for all input and output buffers. + + The number of input/output buffers must not exceed ETHOSU_FD_MAX value defined in the kernel module + uapi/ethosu.h. + + Destruction of the object closes inference file descriptor. + ") Inference; +%nodefaultctor Inference; +class Inference { +public: + + %feature("docstring", + " + Polls inference file descriptor for events. + + Args: + timeoutNanos (int64_t): polling timeout in nanoseconds. + + Returns: + bool: True for success, False otherwise. + ") wait; + void wait(int64_t timeoutNanos = -1) const; + + %feature("docstring", + " + Aborts the current inference job. + + Returns: + bool: True if gracefully stopped, False otherwise. + ") cancel; + bool cancel() const; + + %feature("docstring", + " + Gets the current inference job status. + + Returns: + InferenceStatus. + ") status; + EthosU::InferenceStatus status() const; + + %feature("docstring", + " + Returns inference file descriptor. + + Returns: + int: file descriptor id + ") getFd; + int getFd() const; + + %feature("docstring", + " + Returns associated `Network` object. + + Returns: + `Network`: network used during initialisation + ") getNetwork; + std::shared_ptr<Network> getNetwork() const; + + %feature("docstring", + " + Returns copied input feature maps buffers. + + Returns: + list: input feature map buffers + ") getIfmBuffers; + std::vector<std::shared_ptr<Buffer>> &getIfmBuffers(); + + %feature("docstring", + " + Returns copied output feature maps buffers. + + Returns: + list: output feature map buffers + ") getOfmBuffers; + std::vector<std::shared_ptr<Buffer>> &getOfmBuffers(); + + %feature("docstring", + " + Returns PMU event data. + + Returns: + list: PMU event data + ") getPmuCounters; + const std::vector<uint32_t> getPmuCounters(); + + %feature("docstring", + " + Returns the total cycle count, including idle cycles, as reported by the PMU. + + Returns: + int: total cycle count + ") getCycleCounter; + uint64_t getCycleCounter(); + + %feature("docstring", + " + Returns maximum supported number of PMU events. + + Returns: + int: PMU event max + ") getMaxPmuEventCounters; + static uint32_t getMaxPmuEventCounters(); +}; + +%extend Inference { + Inference(const std::shared_ptr<Network> &network, + const std::vector<std::shared_ptr<Buffer>> &ifm, + const std::vector<std::shared_ptr<Buffer>> &ofm) + { + return new EthosU::Inference(network, ifm.begin(), ifm.end(), ofm.begin(), ofm.end()); + } + Inference(const std::shared_ptr<Network> & network, + const std::vector<std::shared_ptr<Buffer>> &ifm, + const std::vector<std::shared_ptr<Buffer>> &ofm, + const std::vector<unsigned int> &enabledCounters, + bool enableCycleCounter) + { + return new EthosU::Inference(network, ifm.begin(), ifm.end(), ofm.begin(), ofm.end(), enabledCounters, enableCycleCounter); + } +} + +} +// Clear exception typemap. +%exception; diff --git a/driver_library/python/src/ethosu_driver/swig/standard_header.i b/driver_library/python/src/ethosu_driver/swig/standard_header.i new file mode 100644 index 0000000..03cf015 --- /dev/null +++ b/driver_library/python/src/ethosu_driver/swig/standard_header.i @@ -0,0 +1,50 @@ +// +// SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +// SPDX-License-Identifier: Apache-2.0 +// +%include "stl.i" +%include "cstring.i" +%include "std_string.i" +%include "std_vector.i" +%include "std_unordered_set.i" +%include "std_pair.i" +%include "stdint.i" +%include "carrays.i" +%include "exception.i" +%include "typemaps.i" +%include "std_iostream.i" +%include "std_shared_ptr.i" + +%ignore *::operator=; +%ignore *::operator[]; + + +// Define exception typemap to wrap exception into python exception. + +%exception{ + try { + $action + } catch (const EthosU::Exception& e) { + SWIG_exception(SWIG_RuntimeError, const_cast<char*>(e.what())); + } +}; + +%exception __getitem__ { + try { + $action + } catch (const std::out_of_range &e) { + SWIG_exception(SWIG_IndexError, const_cast<char*>(e.what())); + } catch (const std::exception &e) { + SWIG_exception(SWIG_RuntimeError, const_cast<char*>(e.what())); + } +}; + +%exception __setitem__ { + try { + $action + } catch (const std::out_of_range &e) { + SWIG_exception(SWIG_IndexError, const_cast<char*>(e.what())); + } catch (const std::exception &e) { + SWIG_exception(SWIG_RuntimeError, const_cast<char*>(e.what())); + } +}; diff --git a/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i b/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i new file mode 100644 index 0000000..13b7909 --- /dev/null +++ b/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i @@ -0,0 +1,42 @@ +// +// SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com> +// SPDX-License-Identifier: Apache-2.0 +// +%define %mutable_buffer(TYPEMAP, SIZE) + %typemap(in) (TYPEMAP, SIZE) { + int res; void *buf = 0; size_t size = 0; + Py_buffer view; + res = PyObject_GetBuffer($input, &view, PyBUF_WRITABLE); + buf = view.buf; + size = view.len; + PyBuffer_Release(&view); + if (res < 0) { + PyErr_Clear(); + %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); + } + $1 = ($1_ltype) buf; + $2 = ($2_ltype) size; + } + + %typemap(typecheck) (TYPEMAP, SIZE) { + $1 = PyObject_CheckBuffer($input) || PyTuple_Check($input) ? 1 : 0; + } +%enddef + +%define %clear_mutable_buffer(TYPEMAP, SIZE) + %typemap(in) (TYPEMAP, SIZE); + %typemap(typecheck) (TYPEMAP, SIZE); +%enddef + + +%define %driver_buffer_out + %typemap(out) (char*) { + auto size = arg1->size(); + int readOnly = 0; + $result = PyMemoryView_FromMemory($1, size, readOnly); + } +%enddef + +%define %clear_driver_buffer_out + %typemap(out) (char*); +%enddef |