Skip to content

Commit 8de8a46

Browse files
committed
[onert] Add BulkPipelineBuffer for NPU buffer management
This commit introduces the BulkPipelineBuffer class to manage the buffers in the TRIX backend. ONt-DCO-1.0-ONE-DCO-1.0-Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
1 parent a5315f0 commit 8de8a46

5 files changed

Lines changed: 351 additions & 0 deletions

File tree

runtime/onert/backend/trix/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ message(STATUS "ONERT backend: Found TRIXEngine")
99

1010
file(GLOB_RECURSE SOURCES "*.cc")
1111

12+
file(GLOB_RECURSE TESTS "*.test.cc")
13+
list(REMOVE_ITEM SOURCES ${TESTS})
14+
1215
add_library(${LIB_ONERT_BACKEND_TRIX} SHARED ${SOURCES})
1316

1417
target_link_libraries(${LIB_ONERT_BACKEND_TRIX} PRIVATE onert_core)
@@ -24,3 +27,23 @@ set_target_properties(${LIB_ONERT_BACKEND_TRIX} PROPERTIES
2427
INSTALL_RPATH ${ONERT_RPATH_PLUGIN})
2528

2629
install(TARGETS ${LIB_ONERT_BACKEND_TRIX} DESTINATION ${ONERT_INSTALL_BACKENDDIR})
30+
31+
if(NOT ENABLE_TEST)
32+
return()
33+
endif(NOT ENABLE_TEST)
34+
35+
# Unit Tests
36+
set(TEST_ONERT_TRIX_BACKEND test_onert_trix_backend)
37+
38+
add_executable(${TEST_ONERT_TRIX_BACKEND} ${TESTS})
39+
target_link_libraries(${TEST_ONERT_TRIX_BACKEND} onert_core)
40+
target_link_libraries(${TEST_ONERT_TRIX_BACKEND} trix-engine)
41+
target_link_libraries(${TEST_ONERT_TRIX_BACKEND} ${LIB_ONERT_BACKEND_TRIX})
42+
target_link_libraries(${TEST_ONERT_TRIX_BACKEND} nnfw_common)
43+
target_link_libraries(${TEST_ONERT_TRIX_BACKEND} nnfw_coverage)
44+
target_link_libraries(${TEST_ONERT_TRIX_BACKEND} gtest gtest_main Threads::Threads)
45+
set_target_properties(${TEST_ONERT_TRIX_BACKEND} PROPERTIES
46+
INSTALL_RPATH "$ORIGIN/../${ONERT_INSTALL_COREDIR}:$ORIGIN/../${ONERT_INSTALL_BACKENDDIR}")
47+
48+
add_test(${TEST_ONERT_TRIX_BACKEND} ${TEST_ONERT_TRIX_BACKEND})
49+
install(TARGETS ${TEST_ONERT_TRIX_BACKEND} DESTINATION unittest)
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "BulkPipelineBuffer.h"
18+
19+
#include <fcntl.h>
20+
#include <sys/ioctl.h>
21+
#include <sys/mman.h>
22+
#include <unistd.h>
23+
#include <cstring>
24+
#include <iostream>
25+
26+
namespace onert
27+
{
28+
namespace backend
29+
{
30+
namespace trix
31+
{
32+
namespace ops
33+
{
34+
35+
// FIXME: Using higher level API instead of raw API
36+
struct trix_ioctl_hwmem
37+
{
38+
int32_t type;
39+
uint64_t size;
40+
int32_t dbuf_fd;
41+
} __attribute__((packed));
42+
43+
#define TRIX_IOCTL_HWMEM_ALLOC _IOW(136, 21, struct trix_ioctl_hwmem)
44+
#define TRIX_IOCTL_HWMEM_DEALLOC _IOW(136, 22, struct trix_ioctl_hwmem)
45+
46+
BulkPipelineBuffer::BulkPipelineBuffer(BufferType type, size_t size, int device_id)
47+
: _type(type), _size(size), _device_id(device_id)
48+
{
49+
// DO NOTHING
50+
}
51+
52+
BulkPipelineBuffer::~BulkPipelineBuffer() { deallocate(); }
53+
54+
size_t BulkPipelineBuffer::size() const { return _buffer ? _buffer->size : 0; }
55+
56+
bool BulkPipelineBuffer::isReady() const { return _buffer && _buffer->addr != nullptr; }
57+
58+
void BulkPipelineBuffer::allocate()
59+
{
60+
if (_buffer && _buffer->addr != nullptr)
61+
{
62+
// Already allocated
63+
return;
64+
}
65+
66+
if (!_buffer)
67+
{
68+
_buffer = new generic_buffer{};
69+
}
70+
71+
// Open the devbice
72+
char devname[16];
73+
snprintf(devname, sizeof(devname), "/dev/triv2-%d", _device_id);
74+
_dev_fd = open(devname, O_RDWR);
75+
if (_dev_fd < 0)
76+
{
77+
throw std::runtime_error("Failed to open NPU device: " + std::string(devname));
78+
}
79+
80+
// Allocate a buffer
81+
struct trix_ioctl_hwmem hwmem;
82+
hwmem.type = (_type == BufferType::DMABUF_CONT) ? 0 : 1;
83+
hwmem.size = getAlignedSize(_size);
84+
85+
_buffer->dmabuf = ioctl(_dev_fd, TRIX_IOCTL_HWMEM_ALLOC, &hwmem);
86+
if (_buffer->dmabuf < 0)
87+
{
88+
close(_dev_fd);
89+
_dev_fd = -1;
90+
throw std::runtime_error("Failed to allocate DMA buffer, size: " + std::to_string(hwmem.size));
91+
}
92+
93+
// Mapping the buffer
94+
_buffer->addr = mmap(nullptr, hwmem.size, PROT_READ | PROT_WRITE, MAP_SHARED, _buffer->dmabuf, 0);
95+
if (_buffer->addr == MAP_FAILED)
96+
{
97+
close(_buffer->dmabuf);
98+
close(_dev_fd);
99+
_buffer->dmabuf = -1;
100+
_dev_fd = -1;
101+
_buffer->addr = nullptr;
102+
throw std::runtime_error("Failed to mmap DMA buffer");
103+
}
104+
105+
_buffer->size = _size;
106+
_buffer->type = BUFFER_DMABUF;
107+
}
108+
109+
void BulkPipelineBuffer::deallocate()
110+
{
111+
if (!_buffer)
112+
{
113+
return;
114+
}
115+
116+
if (_buffer->addr != nullptr)
117+
{
118+
size_t aligned_sz = getAlignedSize(_buffer->size);
119+
munmap(_buffer->addr, aligned_sz);
120+
_buffer->addr = nullptr;
121+
}
122+
123+
if (_buffer->dmabuf >= 0)
124+
{
125+
struct trix_ioctl_hwmem hwmem;
126+
hwmem.dbuf_fd = _buffer->dmabuf;
127+
ioctl(_dev_fd, TRIX_IOCTL_HWMEM_DEALLOC, &hwmem);
128+
close(_buffer->dmabuf);
129+
_buffer->dmabuf = -1;
130+
}
131+
132+
if (_dev_fd >= 0)
133+
{
134+
close(_dev_fd);
135+
_dev_fd = -1;
136+
}
137+
138+
delete _buffer;
139+
_buffer = nullptr;
140+
}
141+
142+
void BulkPipelineBuffer::fillFromFile(FILE *fp, size_t offset)
143+
{
144+
if (!isReady())
145+
{
146+
throw std::runtime_error("Buffer is not allocated");
147+
}
148+
149+
if (!fp)
150+
{
151+
throw std::runtime_error("Invalid file pointer");
152+
}
153+
154+
if (fseek(fp, static_cast<long>(offset), SEEK_SET) != 0)
155+
{
156+
throw std::runtime_error("Failed to seek file to offset: " + std::to_string(offset));
157+
}
158+
159+
if (fread(_buffer->addr, _buffer->size, 1, fp) != 1)
160+
{
161+
throw std::runtime_error("Failed to read " + std::to_string(_buffer->size) +
162+
" bytes from file");
163+
}
164+
}
165+
166+
size_t BulkPipelineBuffer::getAlignedSize(size_t size) const
167+
{
168+
// 4 KB (= Page size) aligned size
169+
constexpr size_t _4KB_M_1 = (1 << 12) - 1;
170+
return (size + _4KB_M_1) & ~_4KB_M_1;
171+
}
172+
173+
} // namespace ops
174+
} // namespace trix
175+
} // namespace backend
176+
} // namespace onert
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef __ONERT_BACKEND_TRIX_OPS_BULKPIPELINEBUFFER_H__
18+
#define __ONERT_BACKEND_TRIX_OPS_BULKPIPELINEBUFFER_H__
19+
20+
#include <memory>
21+
#include <cstdio>
22+
#include <stdexcept>
23+
#include <libnpuhost.h>
24+
25+
namespace onert
26+
{
27+
namespace backend
28+
{
29+
namespace trix
30+
{
31+
namespace ops
32+
{
33+
34+
class BulkPipelineBuffer
35+
{
36+
public:
37+
enum class BufferType
38+
{
39+
DMABUF_CONT, // Contiguous DMA buffer
40+
DMABUF_IOMMU // IOMMU DMA buffer
41+
};
42+
43+
public:
44+
BulkPipelineBuffer(BufferType type, size_t size, int device_id);
45+
~BulkPipelineBuffer();
46+
47+
// Disallow copying
48+
BulkPipelineBuffer(const BulkPipelineBuffer &) = delete;
49+
BulkPipelineBuffer &operator=(const BulkPipelineBuffer &) = delete;
50+
51+
// Buffer management functions
52+
void allocate();
53+
void deallocate();
54+
size_t size() const;
55+
56+
generic_buffer *getGenericBuffer() { return _buffer; }
57+
58+
// Data manipulation functions
59+
void fillFromFile(FILE *fp, size_t offset = 0);
60+
bool isReady() const;
61+
62+
private:
63+
size_t getAlignedSize(size_t size) const;
64+
65+
private:
66+
BufferType _type;
67+
size_t _size;
68+
int _device_id;
69+
int _dev_fd{-1};
70+
generic_buffer *_buffer{nullptr};
71+
};
72+
73+
} // namespace ops
74+
} // namespace trix
75+
} // namespace backend
76+
} // namespace onert
77+
78+
#endif // __ONERT_BACKEND_TRIX_OPS_BULKPIPELINEBUFFER_H__
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "../BulkPipelineBuffer.h"
2+
#include <gtest/gtest.h>
3+
4+
#include "mock_syscalls.h"
5+
6+
using namespace onert::backend::trix::ops;
7+
8+
class BulkPipelineBufferTest : public ::testing::Test
9+
{
10+
protected:
11+
void SetUp() override
12+
{
13+
// Create a standard buffer for testing
14+
buffer =
15+
std::make_unique<BulkPipelineBuffer>(BulkPipelineBuffer::BufferType::DMABUF_CONT, 1024, 0);
16+
}
17+
18+
void TearDown() override
19+
{
20+
// Ensure buffer is properly deallocated
21+
if (buffer && buffer->isReady())
22+
{
23+
buffer->deallocate();
24+
}
25+
}
26+
27+
std::unique_ptr<BulkPipelineBuffer> buffer;
28+
};
29+
30+
TEST_F(BulkPipelineBufferTest, test_allocate)
31+
{
32+
EXPECT_NO_THROW(buffer->allocate());
33+
EXPECT_TRUE(buffer->isReady());
34+
EXPECT_EQ(buffer->size(), 1024);
35+
}
36+
37+
TEST_F(BulkPipelineBufferTest, test_deallocate)
38+
{
39+
buffer->allocate();
40+
buffer->deallocate();
41+
EXPECT_FALSE(buffer->isReady());
42+
EXPECT_EQ(buffer->size(), 0);
43+
}
44+
45+
TEST_F(BulkPipelineBufferTest, test_fillFromFile)
46+
{
47+
auto dummy_fp = fopen("/dev/null", "r");
48+
ASSERT_NE(dummy_fp, nullptr) << "Failed to open /dev/null for testing";
49+
50+
EXPECT_ANY_THROW(buffer->fillFromFile(nullptr, 0));
51+
52+
buffer->allocate();
53+
EXPECT_NO_THROW(buffer->fillFromFile(dummy_fp, 0));
54+
buffer->deallocate();
55+
56+
fclose(dummy_fp);
57+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef _MOCK_SYSCALLS_H_
2+
#define _MOCK_SYSCALLS_H_
3+
4+
#include <sys/mman.h>
5+
#include <sys/ioctl.h>
6+
#include <fcntl.h>
7+
#include <stdio.h>
8+
9+
int open(const char *, int, ...) { return 0; }
10+
void *mmap(void *, size_t, int, int, int, off_t) { return (void *)0x1; }
11+
int munmap(void *, size_t) { return 0; }
12+
int close(int) { return 0; }
13+
int ioctl(int, unsigned long, ...) { return 0; }
14+
size_t fread(void *, size_t, size_t, FILE *) { return 1; }
15+
int fseek(FILE *, long, int) { return 0; }
16+
17+
#endif

0 commit comments

Comments
 (0)