Skip to content

Commit 20234f3

Browse files
Feature: Enable Memory Zero-Copy
- Open Model with zero-copy using dmabufheap - Improve model loading with zero-copy - Remove unncessary comments or headers. Change file name - remove enn api from default extension/file_data_loader Co-authored-by: Hoon Choi <hoon98.choi@samsung.com> Signed-off-by: Jiseong oh <jiseong.oh@samsung.com>
1 parent 3a6314e commit 20234f3

File tree

14 files changed

+905
-43
lines changed

14 files changed

+905
-43
lines changed

backends/samsung/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ if(${ANDROID})
1717
enn_backend
1818
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/enn_backend.cpp
1919
${CMAKE_CURRENT_LIST_DIR}/enn_executor.cpp
20+
${CMAKE_CURRENT_LIST_DIR}/enn_shared_memory_manager.cpp
2021
${CMAKE_CURRENT_LIST_DIR}/enn_api_implementation.cpp
2122
)
2223
endif()

backends/samsung/runtime/enn_api_implementation.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,27 @@ void* loadApiFunction(void* handle, const char* name, bool optional) {
3333
return fn;
3434
}
3535

36-
std::mutex EnnApi::instance_mutex_;
37-
3836
EnnApi* EnnApi::getEnnApiInstance() {
39-
std::lock_guard<std::mutex> lgd(instance_mutex_);
4037
static EnnApi enn_api;
41-
if (!enn_api.getInitialize()) {
42-
auto status = enn_api.loadApiLib();
43-
if (status == Error::Ok) {
44-
ENN_LOG_INFO("Loading ENN API library Completed.")
45-
enn_api.initialize_ = true;
46-
} else {
47-
ENN_LOG_ERROR("Failed to load enn api library. %s", dlerror());
48-
}
49-
}
5038
return &enn_api;
5139
}
5240

53-
EnnApi::~EnnApi() {
54-
std::lock_guard<std::mutex> lgd(instance_mutex_);
55-
if (getInitialize()) {
56-
unloadApiLib();
41+
EnnApi::EnnApi() {
42+
auto status = loadApiLib();
43+
if (status == Error::Ok) {
44+
ET_LOG(Info, "Loading ENN API library Completed.");
45+
EnnInitialize();
46+
initialize_ = true;
47+
} else {
48+
ET_LOG(Error, "Failed to load enn api library. %s", dlerror());
5749
}
5850
}
5951

60-
bool EnnApi::getInitialize() const {
61-
return initialize_;
52+
EnnApi::~EnnApi() {
53+
if (initialize_) {
54+
EnnDeinitialize();
55+
unloadApiLib();
56+
}
6257
}
6358

6459
Error EnnApi::loadApiLib() {
@@ -76,6 +71,7 @@ Error EnnApi::loadApiLib() {
7671
ENN_LOAD_API_FUNC(libenn_public_api_, EnnUnsetFastIpc, this);
7772
ENN_LOAD_API_FUNC(libenn_public_api_, EnnExecuteModelFastIpc, this);
7873
ENN_LOAD_API_FUNC(libenn_public_api_, EnnExecuteModel, this);
74+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnCreateBuffer, this);
7975
ENN_LOAD_API_FUNC(
8076
libenn_public_api_, EnnExecuteModelWithSessionIdAsync, this);
8177
ENN_LOAD_API_FUNC(libenn_public_api_, EnnExecuteModelWithSessionIdWait, this);
@@ -87,13 +83,18 @@ Error EnnApi::loadApiLib() {
8783
ENN_LOAD_API_FUNC(libenn_public_api_, EnnBufferCommit, this);
8884
ENN_LOAD_API_FUNC(libenn_public_api_, EnnGetBuffersInfo, this);
8985
ENN_LOAD_API_FUNC(libenn_public_api_, EnnReleaseBuffers, this);
86+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnCreateBuffer, this);
87+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnReleaseBuffer, this);
88+
ENN_LOAD_API_FUNC(
89+
libenn_public_api_, EnnGetFileDescriptorFromEnnBuffer, this);
90+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnOpenModelFromFd, this);
9091

9192
return Error::Ok;
9293
}
9394

9495
Error EnnApi::unloadApiLib() {
9596
if (dlclose(libenn_public_api_) != 0) {
96-
ENN_LOG_ERROR("Failed to close ENN API library. %s", dlerror());
97+
ET_LOG(Error, "Failed to close ENN API library. %s", dlerror());
9798
return Error::Internal;
9899
}
99100
libenn_public_api_ = nullptr;

backends/samsung/runtime/enn_api_implementation.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class EnnApi {
3737
const char* va,
3838
const uint32_t size,
3939
EnnModelId* model_id);
40+
EnnReturn (*EnnOpenModelFromFd)(int _fd, EnnModelId* model_id);
4041
EnnReturn (*EnnSetFastIpc)(void);
4142
EnnReturn (*EnnUnsetFastIpc)(void);
4243
EnnReturn (*EnnExecuteModelFastIpc)(
@@ -67,6 +68,13 @@ class EnnApi {
6768
NumberOfBuffersInfo* buffers_info);
6869
EnnReturn (
6970
*EnnReleaseBuffers)(EnnBufferPtr* buffers, const int32_t numOfBuffers);
71+
EnnReturn (*EnnCreateBuffer)(
72+
const uint32_t req_size,
73+
const uint32_t ion_flag,
74+
EnnBufferPtr* out);
75+
EnnReturn (*EnnReleaseBuffer)(EnnBufferPtr buf);
76+
EnnReturn (
77+
*EnnGetFileDescriptorFromEnnBuffer)(EnnBufferPtr buffer, int32_t* fd);
7078

7179
private:
7280
static std::mutex instance_mutex_;
@@ -75,7 +83,7 @@ class EnnApi {
7583
void* libenn_public_api_ = nullptr;
7684
static std::atomic<int> ref_count_;
7785

78-
EnnApi() = default;
86+
EnnApi();
7987
bool getInitialize() const;
8088
Error loadApiLib();
8189
Error unloadApiLib();
@@ -120,6 +128,14 @@ typedef EnnReturn (*EnnGetBuffersInfo_fn)(
120128
NumberOfBuffersInfo* buffers_info);
121129
typedef EnnReturn (
122130
*EnnReleaseBuffers_fn)(EnnBufferPtr* buffers, const int32_t numOfBuffers);
131+
typedef EnnReturn (*EnnCreateBuffer_fn)(
132+
const uint32_t req_size,
133+
const uint32_t ion_flag,
134+
EnnBufferPtr* out);
135+
typedef EnnReturn (*EnnReleaseBuffer_fn)(EnnBufferPtr buf);
136+
typedef EnnReturn (
137+
*EnnGetFileDescriptorFromEnnBuffer_fn)(EnnBufferPtr buffer, int32_t* fd);
138+
typedef EnnReturn (*EnnOpenModelFromFd_fn)(int _fd, EnnModelId* model_id);
123139

124140
} // namespace enn
125141
} // namespace executor

backends/samsung/runtime/enn_backend.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <executorch/backends/samsung/runtime/enn_executor.h>
1010
#include <executorch/backends/samsung/runtime/logging.h>
1111
#include <executorch/backends/samsung/runtime/profile.hpp>
12+
1213
#include <executorch/runtime/backend/interface.h>
1314
#include <executorch/runtime/core/error.h>
1415
#include <executorch/runtime/core/evalue.h>

backends/samsung/runtime/enn_executor.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@
77
*
88
*/
99
#include <executorch/backends/samsung/runtime/enn_executor.h>
10+
#include <executorch/backends/samsung/runtime/enn_shared_memory_manager.h>
1011
#include <executorch/backends/samsung/runtime/logging.h>
1112
#include <executorch/backends/samsung/runtime/profile.hpp>
12-
#include <inttypes.h>
1313

14+
#include <android/log.h>
15+
#include <inttypes.h>
16+
#include <sys/mman.h>
17+
#include <sys/types.h>
18+
#include <unistd.h>
1419
#include <fstream>
1520
#include <string>
1621
#include <vector>
@@ -19,23 +24,54 @@ namespace torch {
1924
namespace executor {
2025
namespace enn {
2126

27+
uint32_t get_size_from_fd(int fd) {
28+
if (fd < 0) {
29+
ET_LOG(Error, "get_size_from_fd(), invalid fd(%d)\n", fd);
30+
return 0;
31+
} else {
32+
off_t file_size = lseek(fd, 0, SEEK_END);
33+
if (file_size < 0) {
34+
return 0;
35+
} else {
36+
return static_cast<uint32_t>(file_size);
37+
}
38+
}
39+
}
40+
2241
Error EnnExecutor::initialize(const char* binary_buf_addr, size_t buf_size) {
2342
EXYNOS_ATRACE_FUNCTION_LINE();
43+
auto _sm_instance = executorch::backends::enn::shared_memory_manager::
44+
SharedMemoryManager::getInstance();
2445
const EnnApi* enn_api_inst = EnnApi::getEnnApiInstance();
25-
auto ret = enn_api_inst->EnnInitialize();
26-
ET_CHECK_OR_RETURN_ERROR(
27-
ret == ENN_RET_SUCCESS, Internal, "Enn initialize failed.");
46+
EnnReturn ret;
2847

2948
ET_LOG(Info, "Start to open model %p, %ld", binary_buf_addr, buf_size);
30-
ret = enn_api_inst->EnnOpenModelFromMemory(
31-
binary_buf_addr, buf_size, &model_id_);
3249

50+
EnnBufferPtr _out;
51+
if (_sm_instance->query(&_out, binary_buf_addr, buf_size)) {
52+
int fd;
53+
if (_out->va == binary_buf_addr &&
54+
!enn_api_inst->EnnGetFileDescriptorFromEnnBuffer(_out, &fd)) {
55+
ret = enn_api_inst->EnnOpenModelFromFd(fd, &model_id_);
56+
ET_LOG(Info, "Opened Model From File Descriptor");
57+
if (ret == ENN_RET_SUCCESS) {
58+
ET_LOG(Info, "Buffer Loading finished with fd, so fd would be closed");
59+
_sm_instance->free(_out->va);
60+
}
61+
}
62+
}
63+
if (!model_id_) {
64+
ET_LOG(Info, "Opened Model From Memory");
65+
ret = enn_api_inst->EnnOpenModelFromMemory(
66+
binary_buf_addr, buf_size, &model_id_);
67+
}
3368
ET_CHECK_OR_RETURN_ERROR(
3469
ret == ENN_RET_SUCCESS,
3570
Internal,
3671
"Failed to load Enn model from buffer %d",
3772
(int)ret);
3873
ET_LOG(Info, "Open successfully.");
74+
3975
NumberOfBuffersInfo buffers_info;
4076
ret = enn_api_inst->EnnAllocateAllBuffersWithSessionId(
4177
model_id_, &alloc_buffer_, &buffers_info, 0, true);

backends/samsung/runtime/enn_executor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class EnnExecutor {
4040
~EnnExecutor();
4141

4242
private:
43-
EnnModelId model_id_;
43+
EnnModelId model_id_ = 0ULL;
4444
EnnBufferPtr* alloc_buffer_ = nullptr;
4545
int32_t num_of_inputs_ = 0;
4646
int32_t num_of_outputs_ = 0;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2025 Samsung Electronics Co. LTD
3+
* All rights reserved
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*
8+
*/
9+
#include <executorch/backends/samsung/runtime/enn_api_implementation.h>
10+
#include <executorch/backends/samsung/runtime/enn_shared_memory_manager.h>
11+
#include <executorch/backends/samsung/runtime/enn_type.h>
12+
#include <executorch/backends/samsung/runtime/logging.h>
13+
#include <executorch/runtime/core/error.h>
14+
15+
#include <mutex>
16+
#include <vector>
17+
18+
using namespace torch::executor::enn;
19+
using namespace torch::executor;
20+
21+
namespace executorch {
22+
namespace backends {
23+
namespace enn {
24+
namespace shared_memory_manager {
25+
26+
static std::mutex instance_mutex_;
27+
28+
SharedMemoryManager* SharedMemoryManager::getInstance() {
29+
static SharedMemoryManager instance;
30+
return &instance;
31+
}
32+
33+
void* SharedMemoryManager::alloc(const size_t size) {
34+
std::lock_guard<std::mutex> lgd(instance_mutex_);
35+
auto enn_api_inst = EnnApi::getEnnApiInstance();
36+
EnnBufferPtr bufferPtr;
37+
auto ret = enn_api_inst->EnnCreateBuffer(size, 0, &bufferPtr);
38+
if (ret) {
39+
ET_LOG(Error, "Buffer Creation Error");
40+
return nullptr;
41+
}
42+
EnnBufferPtrList.emplace_back(bufferPtr);
43+
return bufferPtr->va;
44+
}
45+
46+
bool SharedMemoryManager::query(
47+
EnnBufferPtr* out,
48+
const void* ptr,
49+
const size_t size) {
50+
std::lock_guard<std::mutex> lgd(instance_mutex_);
51+
auto enn_api_inst = EnnApi::getEnnApiInstance();
52+
for (const auto& buffer : EnnBufferPtrList) {
53+
if (buffer->va <= ptr &&
54+
ptr < static_cast<char*>(buffer->va) + buffer->size) {
55+
int fd;
56+
auto ret = enn_api_inst->EnnGetFileDescriptorFromEnnBuffer(buffer, &fd);
57+
if (ret) {
58+
ET_LOG(
59+
Info,
60+
"va: %p, size: %zu is in LUT, but failed to get FileDescriptor",
61+
ptr,
62+
size);
63+
return false;
64+
}
65+
*out = buffer;
66+
return true;
67+
}
68+
}
69+
ET_LOG(Info, "va: %p, size: %zu is not in LUT", ptr, size);
70+
*out = nullptr;
71+
return false;
72+
}
73+
74+
void SharedMemoryManager::free(void* ptr) {
75+
free(ptr, {});
76+
}
77+
void SharedMemoryManager::free(void* ptr, std::align_val_t alignment) {
78+
std::lock_guard<std::mutex> lgd(instance_mutex_);
79+
auto enn_api_inst = EnnApi::getEnnApiInstance();
80+
for (auto it = EnnBufferPtrList.begin(); it != EnnBufferPtrList.end(); ++it) {
81+
if ((*it)->va == ptr) {
82+
ET_LOG(
83+
Info,
84+
"va(%p), size(%d), offset(%d) is erased from LUT",
85+
ptr,
86+
(*it)->size,
87+
(*it)->offset);
88+
auto ret = enn_api_inst->EnnReleaseBuffer(*it);
89+
if (ret) {
90+
ET_LOG(Error, "Failed to destroy buffer: %p", ptr);
91+
}
92+
EnnBufferPtrList.erase(it);
93+
ET_LOG(Info, "Buffer Erased(%p)", ptr);
94+
return;
95+
}
96+
}
97+
}
98+
99+
} // namespace shared_memory_manager
100+
} // namespace enn
101+
} // namespace backends
102+
} // namespace executorch
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2025 Samsung Electronics Co. LTD
3+
* All rights reserved
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*
8+
*/
9+
#pragma once
10+
11+
#include <executorch/backends/samsung/runtime/enn_api_implementation.h>
12+
#include <executorch/backends/samsung/runtime/enn_type.h>
13+
#include <executorch/runtime/core/error.h>
14+
15+
#include <vector>
16+
17+
using namespace torch::executor::enn;
18+
19+
namespace executorch {
20+
namespace backends {
21+
namespace enn {
22+
namespace shared_memory_manager {
23+
24+
class SharedMemoryManager {
25+
public:
26+
static SharedMemoryManager* getInstance();
27+
28+
SharedMemoryManager() = default;
29+
~SharedMemoryManager() = default;
30+
SharedMemoryManager(const SharedMemoryManager&) = delete;
31+
SharedMemoryManager& operator=(const SharedMemoryManager&) = delete;
32+
SharedMemoryManager(SharedMemoryManager&&) = delete;
33+
SharedMemoryManager& operator=(SharedMemoryManager&&) = delete;
34+
35+
void* alloc(const size_t size);
36+
void free(void* ptr);
37+
void free(void* ptr, std::align_val_t alignment);
38+
bool query(EnnBufferPtr* out, const void* ptr, const size_t size);
39+
40+
private:
41+
std::vector<EnnBufferPtr> EnnBufferPtrList;
42+
};
43+
44+
} // namespace shared_memory_manager
45+
} // namespace enn
46+
} // namespace backends
47+
} // namespace executorch

0 commit comments

Comments
 (0)