Skip to content

Commit 5bcf795

Browse files
Optimize Enn runner (pytorch#18735)
### Summary * Open Model with zero-copy using dmabufheap * Improve model loading with zero-copy * Remove unncessary comments or headers. Change file name cc @SS-JIA @digantdesai @kimishpatel --------- Signed-off-by: Jiseong oh <jiseong.oh@samsung.com> Signed-off-by: Jiseong Oh <jiseong.oh@samsung.com> Co-authored-by: Hoon Choi <hoon98.choi@samsung.com>
1 parent 33ed3c5 commit 5bcf795

13 files changed

Lines changed: 886 additions & 51 deletions

‎backends/samsung/runtime/CMakeLists.txt‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# logging
88
target_sources(
99
enn_logging
10-
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/logging.h
10+
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/logging.h>
1111
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/logging.cpp
1212
)
1313

@@ -17,6 +17,12 @@ 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
22+
${CMAKE_CURRENT_LIST_DIR}/extension/exynos_file_data_loader.cpp
2123
)
24+
25+
if(BUILD_TESTING)
26+
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/extension/test)
27+
endif()
2228
endif()

‎backends/samsung/runtime/enn_api_implementation.cpp‎

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,35 @@ 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

41+
EnnApi::EnnApi() {
42+
auto status = loadApiLib();
43+
if (status != Error::Ok) {
44+
ET_LOG(Error, "Failed to load enn api library. %s", dlerror());
45+
return;
46+
}
47+
auto ret = EnnInitialize();
48+
if (ret != ENN_RET_SUCCESS) {
49+
ET_LOG(Error, "EnnInitialize failed: %d", static_cast<int>(ret));
50+
unloadApiLib();
51+
return;
52+
}
53+
ET_LOG(Info, "Loading ENN API library Completed.");
54+
initialize_ = true;
55+
}
56+
5357
EnnApi::~EnnApi() {
54-
std::lock_guard<std::mutex> lgd(instance_mutex_);
55-
if (getInitialize()) {
58+
if (initialize_) {
59+
EnnDeinitialize();
5660
unloadApiLib();
5761
}
5862
}
5963

60-
bool EnnApi::getInitialize() const {
64+
bool EnnApi::isInitialized() const {
6165
return initialize_;
6266
}
6367

@@ -87,13 +91,18 @@ Error EnnApi::loadApiLib() {
8791
ENN_LOAD_API_FUNC(libenn_public_api_, EnnBufferCommit, this);
8892
ENN_LOAD_API_FUNC(libenn_public_api_, EnnGetBuffersInfo, this);
8993
ENN_LOAD_API_FUNC(libenn_public_api_, EnnReleaseBuffers, this);
94+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnCreateBuffer, this);
95+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnReleaseBuffer, this);
96+
ENN_LOAD_API_FUNC(
97+
libenn_public_api_, EnnGetFileDescriptorFromEnnBuffer, this);
98+
ENN_LOAD_API_FUNC(libenn_public_api_, EnnOpenModelFromFd, this);
9099

91100
return Error::Ok;
92101
}
93102

94103
Error EnnApi::unloadApiLib() {
95104
if (dlclose(libenn_public_api_) != 0) {
96-
ENN_LOG_ERROR("Failed to close ENN API library. %s", dlerror());
105+
ET_LOG(Error, "Failed to close ENN API library. %s", dlerror());
97106
return Error::Internal;
98107
}
99108
libenn_public_api_ = nullptr;

‎backends/samsung/runtime/enn_api_implementation.h‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class EnnApi {
2828
~EnnApi();
2929

3030
static EnnApi* getEnnApiInstance();
31+
bool isInitialized() const;
3132

3233
EnnReturn (*EnnInitialize)(void);
3334
EnnReturn (*EnnSetPreferencePerfMode)(const uint32_t val);
@@ -37,6 +38,7 @@ class EnnApi {
3738
const char* va,
3839
const uint32_t size,
3940
EnnModelId* model_id);
41+
EnnReturn (*EnnOpenModelFromFd)(int _fd, EnnModelId* model_id);
4042
EnnReturn (*EnnSetFastIpc)(void);
4143
EnnReturn (*EnnUnsetFastIpc)(void);
4244
EnnReturn (*EnnExecuteModelFastIpc)(
@@ -67,6 +69,13 @@ class EnnApi {
6769
NumberOfBuffersInfo* buffers_info);
6870
EnnReturn (
6971
*EnnReleaseBuffers)(EnnBufferPtr* buffers, const int32_t numOfBuffers);
72+
EnnReturn (*EnnCreateBuffer)(
73+
const uint32_t req_size,
74+
const uint32_t ion_flag,
75+
EnnBufferPtr* out);
76+
EnnReturn (*EnnReleaseBuffer)(EnnBufferPtr buf);
77+
EnnReturn (
78+
*EnnGetFileDescriptorFromEnnBuffer)(EnnBufferPtr buffer, int32_t* fd);
7079

7180
private:
7281
static std::mutex instance_mutex_;
@@ -75,8 +84,7 @@ class EnnApi {
7584
void* libenn_public_api_ = nullptr;
7685
static std::atomic<int> ref_count_;
7786

78-
EnnApi() = default;
79-
bool getInitialize() const;
87+
EnnApi();
8088
Error loadApiLib();
8189
Error unloadApiLib();
8290
};
@@ -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: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
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 <fstream>
15-
#include <string>
14+
#include <inttypes.h>
15+
#include <cstring>
1616
#include <vector>
1717

1818
namespace torch {
@@ -21,21 +21,39 @@ namespace enn {
2121

2222
Error EnnExecutor::initialize(const char* binary_buf_addr, size_t buf_size) {
2323
EXYNOS_ATRACE_FUNCTION_LINE();
24+
auto sm_instance = executorch::backends::enn::shared_memory_manager::
25+
SharedMemoryManager::getInstance();
2426
const EnnApi* enn_api_inst = EnnApi::getEnnApiInstance();
25-
auto ret = enn_api_inst->EnnInitialize();
2627
ET_CHECK_OR_RETURN_ERROR(
27-
ret == ENN_RET_SUCCESS, Internal, "Enn initialize failed.");
28+
enn_api_inst->isInitialized(), Internal, "Enn initialize failed.");
29+
EnnReturn ret = ENN_RET_SUCCESS;
2830

29-
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_);
31+
ET_LOG(Info, "Start to open model %p, %zu", binary_buf_addr, buf_size);
3232

33+
EnnBufferPtr shared_buffer = nullptr;
34+
if (sm_instance->query(&shared_buffer, binary_buf_addr, buf_size)) {
35+
int32_t fd;
36+
if (shared_buffer->va == binary_buf_addr &&
37+
!enn_api_inst->EnnGetFileDescriptorFromEnnBuffer(shared_buffer, &fd)) {
38+
ret = enn_api_inst->EnnOpenModelFromFd(fd, &model_id_);
39+
if (ret == ENN_RET_SUCCESS) {
40+
ET_LOG(Info, "Opened model from file descriptor, so fd is closed");
41+
sm_instance->free(shared_buffer->va);
42+
}
43+
}
44+
}
45+
if (!model_id_) {
46+
ET_LOG(Info, "Open model from memory");
47+
ret = enn_api_inst->EnnOpenModelFromMemory(
48+
binary_buf_addr, buf_size, &model_id_);
49+
}
3350
ET_CHECK_OR_RETURN_ERROR(
3451
ret == ENN_RET_SUCCESS,
3552
Internal,
3653
"Failed to load Enn model from buffer %d",
3754
(int)ret);
3855
ET_LOG(Info, "Open successfully.");
56+
3957
NumberOfBuffersInfo buffers_info;
4058
ret = enn_api_inst->EnnAllocateAllBuffersWithSessionId(
4159
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: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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_shared_memory_manager.h>
10+
11+
#include <executorch/backends/samsung/runtime/enn_api_implementation.h>
12+
#include <executorch/backends/samsung/runtime/logging.h>
13+
14+
#include <inttypes.h>
15+
#include <limits>
16+
#include <mutex>
17+
18+
namespace executorch {
19+
namespace backends {
20+
namespace enn {
21+
namespace shared_memory_manager {
22+
23+
using torch::executor::enn::EnnApi;
24+
25+
static std::mutex instance_mutex_;
26+
27+
SharedMemoryManager* SharedMemoryManager::getInstance() {
28+
// Touch the EnnApi singleton first so that it outlives this instance: the
29+
// destructor below releases buffers through the ENN API.
30+
EnnApi::getEnnApiInstance();
31+
static SharedMemoryManager instance;
32+
return &instance;
33+
}
34+
35+
SharedMemoryManager::~SharedMemoryManager() {
36+
std::lock_guard<std::mutex> lgd(instance_mutex_);
37+
auto enn_api_inst = EnnApi::getEnnApiInstance();
38+
for (auto& buffer : buffers_) {
39+
if (enn_api_inst->EnnReleaseBuffer(buffer)) {
40+
ET_LOG(Error, "Failed to destroy buffer: %p", buffer->va);
41+
}
42+
}
43+
buffers_.clear();
44+
}
45+
46+
void* SharedMemoryManager::alloc(const size_t size) {
47+
if (size > std::numeric_limits<uint32_t>::max()) {
48+
ET_LOG(
49+
Error, "Requested size %zu exceeds ENN buffer limit (uint32_t)", size);
50+
return nullptr;
51+
}
52+
std::lock_guard<std::mutex> lgd(instance_mutex_);
53+
auto enn_api_inst = EnnApi::getEnnApiInstance();
54+
EnnBufferPtr bufferPtr;
55+
auto ret = enn_api_inst->EnnCreateBuffer(size, 0, &bufferPtr);
56+
if (ret) {
57+
ET_LOG(Error, "Buffer Creation Error");
58+
return nullptr;
59+
}
60+
buffers_.emplace_back(bufferPtr);
61+
return bufferPtr->va;
62+
}
63+
64+
bool SharedMemoryManager::query(
65+
EnnBufferPtr* out,
66+
const void* ptr,
67+
const size_t size) {
68+
std::lock_guard<std::mutex> lgd(instance_mutex_);
69+
auto enn_api_inst = EnnApi::getEnnApiInstance();
70+
for (const auto& buffer : buffers_) {
71+
if (buffer->va <= ptr &&
72+
ptr < static_cast<char*>(buffer->va) + buffer->size) {
73+
int32_t fd;
74+
auto ret = enn_api_inst->EnnGetFileDescriptorFromEnnBuffer(buffer, &fd);
75+
if (ret) {
76+
ET_LOG(
77+
Info,
78+
"va: %p, size: %zu is in LUT, but failed to get FileDescriptor",
79+
ptr,
80+
size);
81+
return false;
82+
}
83+
*out = buffer;
84+
return true;
85+
}
86+
}
87+
ET_LOG(Info, "va: %p, size: %zu is not in LUT", ptr, size);
88+
*out = nullptr;
89+
return false;
90+
}
91+
92+
void SharedMemoryManager::free(void* ptr) {
93+
std::lock_guard<std::mutex> lgd(instance_mutex_);
94+
auto enn_api_inst = EnnApi::getEnnApiInstance();
95+
for (auto it = buffers_.begin(); it != buffers_.end(); ++it) {
96+
if ((*it)->va == ptr) {
97+
if (enn_api_inst->EnnReleaseBuffer(*it)) {
98+
ET_LOG(
99+
Error,
100+
"Failed to destroy buffer: %p, keeping tracked for retry",
101+
ptr);
102+
return;
103+
}
104+
ET_LOG(
105+
Info,
106+
"va(%p), size(%" PRIu32 "), offset(%" PRIu32 ") is erased from LUT",
107+
ptr,
108+
(*it)->size,
109+
(*it)->offset);
110+
buffers_.erase(it);
111+
return;
112+
}
113+
}
114+
}
115+
116+
} // namespace shared_memory_manager
117+
} // namespace enn
118+
} // namespace backends
119+
} // namespace executorch
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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_type.h>
12+
13+
#include <cstddef>
14+
#include <vector>
15+
16+
namespace executorch {
17+
namespace backends {
18+
namespace enn {
19+
namespace shared_memory_manager {
20+
21+
class SharedMemoryManager {
22+
public:
23+
static SharedMemoryManager* getInstance();
24+
25+
SharedMemoryManager() = default;
26+
~SharedMemoryManager();
27+
SharedMemoryManager(const SharedMemoryManager&) = delete;
28+
SharedMemoryManager& operator=(const SharedMemoryManager&) = delete;
29+
SharedMemoryManager(SharedMemoryManager&&) = delete;
30+
SharedMemoryManager& operator=(SharedMemoryManager&&) = delete;
31+
32+
void* alloc(const size_t size);
33+
void free(void* ptr);
34+
bool query(EnnBufferPtr* out, const void* ptr, const size_t size);
35+
36+
private:
37+
std::vector<EnnBufferPtr> buffers_;
38+
};
39+
40+
} // namespace shared_memory_manager
41+
} // namespace enn
42+
} // namespace backends
43+
} // namespace executorch

0 commit comments

Comments
 (0)