aboutsummaryrefslogtreecommitdiff
path: root/driver_library/python/src
diff options
context:
space:
mode:
authorKshitij Sisodia <kshitij.sisodia@arm.com>2022-09-30 16:42:50 +0100
committerKristofer Jonsson <kristofer.jonsson@arm.com>2022-10-25 16:36:45 +0000
commitf9efe0ddf865c55d28bcaa203fefffa94bf09b42 (patch)
tree928da5f68dafd7e5a0dee05a75f2f6fcd52df170 /driver_library/python/src
parent569aa558f5e7638852a928feede1f21e7323f664 (diff)
downloadethos-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')
-rw-r--r--driver_library/python/src/ethosu_driver/__init__.py6
-rw-r--r--driver_library/python/src/ethosu_driver/_generated/__init__.py2
-rw-r--r--driver_library/python/src/ethosu_driver/_utilities/__init__.py5
-rw-r--r--driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py186
-rw-r--r--driver_library/python/src/ethosu_driver/inference_runner.py100
-rw-r--r--driver_library/python/src/ethosu_driver/swig/driver.i554
-rw-r--r--driver_library/python/src/ethosu_driver/swig/standard_header.i50
-rw-r--r--driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i42
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