aboutsummaryrefslogtreecommitdiff
path: root/driver_library
diff options
context:
space:
mode:
authorMikael Olsson <mikael.olsson@arm.com>2023-10-30 11:10:56 +0100
committerMikael Olsson <mikael.olsson@arm.com>2023-11-06 09:36:00 +0100
commitc081e5954cd92165b139488e76bdfef1402acee6 (patch)
tree32bc237c124e21f12287150cba040c87c8e8b7e3 /driver_library
parent9c999fdd40c0bf2ae420f6f3bfe013dc6baa73c1 (diff)
downloadethos-u-linux-driver-stack-c081e5954cd92165b139488e76bdfef1402acee6.tar.gz
Change create network UAPI to take a user buffer
To not allow the buffer for a network instance to be changed after creation, the create network UAPI will now take the network model data as a user buffer. The content of the user buffer is copied into an internally allocated DMA buffer that cannot be accessed by the user. This breaks the current API so the Linux kernel NPU driver version and the driver library version have been given major version bumps. All the tests, documentation and other applications affected by the changes have been updated accordingly. Change-Id: I25c785d75a24794c3db632e4abe5cfbb1c7ac190 Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
Diffstat (limited to 'driver_library')
-rw-r--r--driver_library/include/ethosu.hpp10
-rw-r--r--driver_library/python/README.md14
-rw-r--r--driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py3
-rw-r--r--driver_library/python/src/ethosu_driver/swig/driver.i51
-rw-r--r--driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i23
-rw-r--r--driver_library/python/test/test_driver.py86
-rw-r--r--driver_library/src/ethosu.cpp15
7 files changed, 117 insertions, 85 deletions
diff --git a/driver_library/include/ethosu.hpp b/driver_library/include/ethosu.hpp
index 47c1868..eaa1ce7 100644
--- a/driver_library/include/ethosu.hpp
+++ b/driver_library/include/ethosu.hpp
@@ -39,12 +39,12 @@
namespace EthosU {
-constexpr uint32_t DRIVER_LIBRARY_VERSION_MAJOR = 2;
+constexpr uint32_t DRIVER_LIBRARY_VERSION_MAJOR = 3;
constexpr uint32_t DRIVER_LIBRARY_VERSION_MINOR = 0;
constexpr uint32_t DRIVER_LIBRARY_VERSION_PATCH = 0;
-constexpr uint32_t MAX_SUPPORTED_KERNEL_DRIVER_MAJOR_VERSION = 2;
-constexpr uint32_t MIN_SUPPORTED_KERNEL_DRIVER_MAJOR_VERSION = 2;
+constexpr uint32_t MAX_SUPPORTED_KERNEL_DRIVER_MAJOR_VERSION = 3;
+constexpr uint32_t MIN_SUPPORTED_KERNEL_DRIVER_MAJOR_VERSION = 3;
class Exception : public std::exception {
public:
@@ -168,12 +168,11 @@ private:
class Network {
public:
- Network(const Device &device, std::shared_ptr<Buffer> &buffer);
+ Network(const Device &device, const unsigned char *networkData, size_t networkSize);
Network(const Device &device, const unsigned index);
virtual ~Network() noexcept(false);
int ioctl(unsigned long cmd, void *data = nullptr);
- std::shared_ptr<Buffer> getBuffer();
const std::vector<size_t> &getIfmDims() const;
size_t getIfmSize() const;
const std::vector<size_t> &getOfmDims() const;
@@ -183,7 +182,6 @@ private:
void collectNetworkInfo();
int fd;
- std::shared_ptr<Buffer> buffer;
std::vector<size_t> ifmDims;
std::vector<size_t> ofmDims;
};
diff --git a/driver_library/python/README.md b/driver_library/python/README.md
index 7fae749..cc67ad9 100644
--- a/driver_library/python/README.md
+++ b/driver_library/python/README.md
@@ -165,8 +165,8 @@ object:
```python
# from file:
-network_file = "/path/to/model.tflite"
-network_buffer = driver.Buffer(device, network_file)
+data_file = "/path/to/data.bin"
+buffer = driver.Buffer(device, data_file)
# from numpy:
ifm_zeros = numpy.zeros(ifm_size, dtype=np.uint8)
@@ -174,11 +174,15 @@ ifm_buffer = driver.Buffer(device, ifm_size)
ifm_buffer.from_buffer(ifm_zeros.data)
```
-To create a network object, provide memory buffer for the model file and
-created device:
+To create a network object, provide the model file or a byte array with the
+network data and the created device:
```python
-network = driver.Network(device, network_buffer)
+# from file:
+network = driver.Network(device, "path/to/model.tflite")
+
+# from byte array:
+network = driver.Network(device, network_data)
```
Inference object is instantiated with a network object and lists of input
diff --git a/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py b/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py
index fcea91f..ca39751 100644
--- a/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py
+++ b/driver_library/python/src/ethosu_driver/_utilities/driver_utilities.py
@@ -30,8 +30,7 @@ def load_model(device: Device, model: str) -> Network:
`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)
+ return Network(device, model)
def populate_buffers(input_data: List[bytearray], buffers: List[Buffer]):
diff --git a/driver_library/python/src/ethosu_driver/swig/driver.i b/driver_library/python/src/ethosu_driver/swig/driver.i
index 3e4e384..6e0ad25 100644
--- a/driver_library/python/src/ethosu_driver/swig/driver.i
+++ b/driver_library/python/src/ethosu_driver/swig/driver.i
@@ -293,12 +293,12 @@ public:
buffer: data to be copied to the mapped memory.
") from_buffer;
- %mutable_buffer(char* buffer, size_t size);
+ %buffer_in(char* buffer, size_t size, BUFFER_FLAG_RW);
void from_buffer(char* buffer, size_t size) {
char* data = $self->data();
std::memcpy(data, buffer, size);
}
- %clear_mutable_buffer(char* buffer, size_t size);
+ %clear_buffer_in(char* buffer, size_t size);
}
%feature("docstring",
@@ -329,15 +329,6 @@ public:
%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:
@@ -374,21 +365,41 @@ public:
};
%extend Network {
- Network(const Device &device, std::shared_ptr<Buffer> &buffer)
+
+ Network(const Device &device, const std::string& filename)
{
- if(buffer == nullptr){
- throw EthosU::Exception(std::string("Failed to create the network, buffer is nullptr.").c_str());
+ std::ifstream stream(filename, std::ios::binary);
+ if (!stream.is_open()) {
+ throw EthosU::Exception(std::string("Failed to open file: ").append(filename).c_str());
}
- auto network = new EthosU::Network(device, buffer);
- return network;
+
+ stream.seekg(0, std::ios_base::end);
+ size_t size = stream.tellg();
+ stream.seekg(0, std::ios_base::beg);
+
+ std::unique_ptr<unsigned char[]> buffer = std::make_unique<unsigned char[]>(size);
+ stream.read(reinterpret_cast<char*>(buffer.get()), size);
+ return new EthosU::Network(device, buffer.get(), size);
}
-}
-%extend Network {
+ %buffer_in(const unsigned char* networkData, size_t networkSize, BUFFER_FLAG_RO);
+ Network(const Device &device, const unsigned char* networkData, size_t networkSize)
+ {
+ if(networkData == nullptr){
+ throw EthosU::Exception(std::string("Failed to create the network, networkData is nullptr.").c_str());
+ }
+
+ if(networkSize == 0U){
+ throw EthosU::Exception(std::string("Failed to create the network, networkSize is zero.").c_str());
+ }
+
+ return new EthosU::Network(device, networkData, networkSize);
+ }
+ %clear_buffer_in(const unsigned char* networkData, size_t networkSize);
+
Network(const Device &device, const unsigned int index)
{
- auto network = new EthosU::Network(device, index);
- return network;
+ return new EthosU::Network(device, index);
}
}
diff --git a/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i b/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i
index 13b7909..bb4627c 100644
--- a/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i
+++ b/driver_library/python/src/ethosu_driver/swig/typemaps/buffer.i
@@ -1,19 +1,25 @@
//
-// SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+// SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
// SPDX-License-Identifier: Apache-2.0
//
-%define %mutable_buffer(TYPEMAP, SIZE)
+
+%define BUFFER_FLAG_RO 0 %enddef
+%define BUFFER_FLAG_RW PyBUF_WRITABLE %enddef
+
+%define %buffer_in(TYPEMAP, SIZE, FLAG)
%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);
+
+ int res = PyObject_GetBuffer($input, &view, FLAG);
if (res < 0) {
PyErr_Clear();
%argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum);
}
+
+ void *buf = view.buf;
+ size_t size = view.len;
+ PyBuffer_Release(&view);
+
$1 = ($1_ltype) buf;
$2 = ($2_ltype) size;
}
@@ -23,12 +29,11 @@
}
%enddef
-%define %clear_mutable_buffer(TYPEMAP, SIZE)
+%define %clear_buffer_in(TYPEMAP, SIZE)
%typemap(in) (TYPEMAP, SIZE);
%typemap(typecheck) (TYPEMAP, SIZE);
%enddef
-
%define %driver_buffer_out
%typemap(out) (char*) {
auto size = arg1->size();
diff --git a/driver_library/python/test/test_driver.py b/driver_library/python/test/test_driver.py
index 0dd207f..e9cb5c8 100644
--- a/driver_library/python/test/test_driver.py
+++ b/driver_library/python/test/test_driver.py
@@ -15,11 +15,14 @@ def device(device_name):
@pytest.fixture()
-def network_buffer(device, model_name, shared_data_folder):
+def network_file(model_name, shared_data_folder):
network_file = os.path.join(shared_data_folder, model_name)
- network_buffer = driver.Buffer(device, network_file)
- yield network_buffer
+ yield network_file
+@pytest.fixture()
+def network(device, network_file):
+ network = driver.Network(device, network_file)
+ yield network
@pytest.mark.parametrize('device_name', ['ethosu0'])
def test_check_device_swig_ownership(device):
@@ -44,12 +47,33 @@ def test_device_wrong_name(device_name):
@pytest.mark.parametrize('device_name', ['ethosu0'])
-def test_driver_network_filenotfound_exception(device, shared_data_folder):
+@pytest.mark.parametrize('model_name', ['model.tflite'])
+def test_driver_network_from_bytearray(device, network_file):
+ network_data = None
+ with open(network_file, 'rb') as file:
+ network_data = file.read()
+ network = driver.Network(device, network_data)
- network_file = os.path.join(shared_data_folder, "some_unknown_model.tflite")
+@pytest.mark.parametrize('device_name', ['ethosu0'])
+def test_driver_network_from_empty_bytearray(device):
with pytest.raises(RuntimeError) as err:
- network_buffer = driver.Buffer(device, network_file)
+ network = driver.Network(device, bytearray())
+
+ assert 'Failed to create the network, networkSize is zero' in str(err.value)
+
+
+@pytest.mark.parametrize('device_name', ['ethosu0'])
+@pytest.mark.parametrize('model_name', ['model.tflite'])
+def test_driver_network_from_file(device, network_file):
+ network = driver.Network(device, network_file)
+
+
+@pytest.mark.parametrize('device_name', ['ethosu0'])
+@pytest.mark.parametrize('model_name', ['some_unknown_model.tflite'])
+def test_driver_network_filenotfound_exception(device, network_file):
+ with pytest.raises(RuntimeError) as err:
+ network = driver.Network(device, network_file)
# Only check for part of the exception since the exception returns
# absolute path which will change on different machines.
@@ -58,57 +82,51 @@ def test_driver_network_filenotfound_exception(device, shared_data_folder):
@pytest.mark.parametrize('device_name', ['ethosu0'])
@pytest.mark.parametrize('model_name', ['model.tflite'])
-def test_check_buffer_swig_ownership(network_buffer):
+def test_check_network_swig_ownership(network):
# Check to see that SWIG has ownership for parser. This instructs SWIG to take
# ownership of the return value. This allows the value to be automatically
# garbage-collected when it is no longer in use
- assert network_buffer.thisown
+ assert network.thisown
@pytest.mark.parametrize('device_name', ['ethosu0'])
@pytest.mark.parametrize('model_name', ['model.tflite'])
-def test_check_buffer_size(network_buffer):
- assert network_buffer.size() > 0
+def test_check_network_ifm_size(device, network):
+ assert network.getIfmSize() > 0
@pytest.mark.parametrize('device_name', ['ethosu0'])
@pytest.mark.parametrize('model_name', ['model.tflite'])
-def test_check_buffer_clear(network_buffer):
- network_buffer.clear()
- for i in range(network_buffer.size()):
- assert network_buffer.data()[i] == 0
+def test_check_network_ofm_size(device, network):
+ assert network.getOfmSize() > 0
@pytest.mark.parametrize('device_name', ['ethosu0'])
-@pytest.mark.parametrize('model_name', ['model.tflite'])
-def test_check_buffer_getFd(network_buffer):
- assert network_buffer.getFd() >= 0
+def test_check_buffer_swig_ownership(device):
+ buffer = driver.Buffer(device, 1024)
+ assert buffer.thisown
@pytest.mark.parametrize('device_name', ['ethosu0'])
-@pytest.mark.parametrize('model_name', ['model.tflite'])
-def test_check_network_ifm_size(device, network_buffer):
- network = driver.Network(device, network_buffer)
- assert network.getIfmSize() > 0
- assert network_buffer.thisown
-
-
-@pytest.mark.parametrize('device_name', [('ethosu0')])
-def test_check_network_buffer_none(device):
+def test_check_buffer_getFd(device):
+ buffer = driver.Buffer(device, 1024)
+ assert buffer.getFd() >= 0
- with pytest.raises(RuntimeError) as err:
- driver.Network(device, None)
- # Only check for part of the exception since the exception returns
- # absolute path which will change on different machines.
- assert 'Failed to create the network' in str(err.value)
+@pytest.mark.parametrize('device_name', ['ethosu0'])
+def test_check_buffer_size(device):
+ buffer = driver.Buffer(device, 1024)
+ assert buffer.size() == 1024
@pytest.mark.parametrize('device_name', ['ethosu0'])
@pytest.mark.parametrize('model_name', ['model.tflite'])
-def test_check_network_ofm_size(device, network_buffer):
- network = driver.Network(device, network_buffer)
- assert network.getOfmSize() > 0
+def test_check_buffer_clear(device, network_file):
+ buffer = driver.Buffer(device, network_file)
+
+ buffer.clear()
+ for i in range(buffer.size()):
+ assert buffer.data()[i] == 0
def test_getMaxPmuEventCounters():
diff --git a/driver_library/src/ethosu.cpp b/driver_library/src/ethosu.cpp
index 3c7dc31..7aec696 100644
--- a/driver_library/src/ethosu.cpp
+++ b/driver_library/src/ethosu.cpp
@@ -333,12 +333,13 @@ int Buffer::getFd() const {
* Network
****************************************************************************/
-Network::Network(const Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buffer(buffer) {
+Network::Network(const Device &device, const unsigned char *networkData, size_t networkSize) : fd(-1) {
// Create buffer handle
ethosu_uapi_network_create uapi;
- uapi.type = ETHOSU_UAPI_NETWORK_BUFFER;
- uapi.fd = buffer->getFd();
- fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
+ uapi.type = ETHOSU_UAPI_NETWORK_USER_BUFFER;
+ uapi.network.data_ptr = reinterpret_cast<uintptr_t>(networkData);
+ uapi.network.size = networkSize;
+ fd = device.ioctl(ETHOSU_IOCTL_NETWORK_CREATE, static_cast<void *>(&uapi));
try {
collectNetworkInfo();
} catch (std::exception &e) {
@@ -348,7 +349,7 @@ Network::Network(const Device &device, shared_ptr<Buffer> &buffer) : fd(-1), buf
throw;
}
- Log(Severity::Info) << "Network(" << &device << ", " << &*buffer << "), this=" << this << ", fd=" << fd << endl;
+ Log(Severity::Info) << "Network(" << &device << "), this=" << this << ", fd=" << fd << endl;
}
Network::Network(const Device &device, const unsigned index) : fd(-1) {
@@ -391,10 +392,6 @@ int Network::ioctl(unsigned long cmd, void *data) {
return eioctl(fd, cmd, data);
}
-shared_ptr<Buffer> Network::getBuffer() {
- return buffer;
-}
-
const std::vector<size_t> &Network::getIfmDims() const {
return ifmDims;
}