Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions backends/samsung/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ X86_64_BUILD_DIR=${PROJECT_DIR}/build_samsung
ANDROID_BUILD_DIR=${PROJECT_DIR}/build_samsung_android
BUILD_ARCH=all
CLEAN_BUILD_DIR=false
BUILD_VULKAN=OFF

EXYNOS_AI_LITECORE_ROOT=${EXYNOS_AI_LITECORE_ROOT}
ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}
Expand All @@ -26,6 +27,9 @@ function usage() {

--build, -b [x86_64, android, all] Default is all, x86_64 target to offline compilation,
android target to online execution.
--vulkan Build the Vulkan backend into executor_runner (android, default is off).
Requires glslc from the Vulkan SDK (1.4.341.1+) in PATH, e.g.
export PATH=\$VULKAN_SDK/bin:\$PATH
--clean, -c Clean the build cache.
--help, -h Print the usage information.
"
Expand Down Expand Up @@ -89,36 +93,30 @@ function build_android() {
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_BUILD_ENN=ON \
-DEXYNOS_AI_LITECORE_ROOT=${EXYNOS_AI_LITECORE_ROOT} \
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
-DEXECUTORCH_BUILD_EXTENSION_FLAT_TENSOR=ON \
-DEXECUTORCH_BUILD_EXTENSION_LLM=ON \
-DEXECUTORCH_BUILD_EXTENSION_LLM_RUNNER=ON \
-DEXECUTORCH_BUILD_EXTENSION_NAMED_DATA_MAP=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-DEXECUTORCH_BUILD_EXTENSION_LLM=ON \
-DEXECUTORCH_BUILD_EXTENSION_LLM_RUNNER=ON \
-DEXECUTORCH_BUILD_EXTENSION_FLAT_TENSOR=ON \
-DEXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL=ON \
-DEXECUTORCH_BUILD_KERNELS_LLM=ON \
-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON \
-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED_PORTABLE=ON \
-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \
-DEXECUTORCH_BUILD_XNNPACK=ON \
-DEXECUTORCH_BUILD_VULKAN=${BUILD_VULKAN} \
-DEXECUTORCH_ENABLE_LOGGING=1 \
-DEXECUTORCH_BUILD_DEVTOOLS=ON \
-DEXECUTORCH_ENABLE_EVENT_TRACER=ON \
-DBUILD_TESTING=OFF \
-S ${PROJECT_DIR} \
-B ${ANDROID_BUILD_DIR}

cmake --build ${ANDROID_BUILD_DIR} -j $(nproc) --target install

LLAMA_EXAMPLE_ROOT=examples/models/llama
cmake ${PROJECT_DIR}/${LLAMA_EXAMPLE_ROOT} \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=${ANDROID_ABI} \
-DCMAKE_INSTALL_PREFIX=${ANDROID_BUILD_DIR} \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_PLATFORM=${ANDROID_PLATFORM} \
-DEXECUTORCH_ENABLE_LOGGING=ON \
-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} \
-B${ANDROID_BUILD_DIR}/${LLAMA_EXAMPLE_ROOT}

cmake --build ${ANDROID_BUILD_DIR}/${LLAMA_EXAMPLE_ROOT} -j $(nproc) --config Release
cmake --build ${ANDROID_BUILD_DIR} -j $(nproc) --target install --config Release
}

# Main
Expand All @@ -133,6 +131,9 @@ do
let i++
ANDROID_NDK_ROOT="${!i}"
;;
"--vulkan")
BUILD_VULKAN=ON
;;
"--clean"|"-c")
CLEAN_BUILD_DIR=true
;;
Expand Down
110 changes: 109 additions & 1 deletion backends/samsung/runtime/enn_api_implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@
*
*/
#include <dlfcn.h>
#include <sys/system_properties.h>

#include <executorch/backends/samsung/runtime/enn_api_implementation.h>
#include <executorch/backends/samsung/runtime/logging.h>

#include <cstring>
#include <string>
#include <unordered_map>

#define ENN_LOAD_API_FUNC(handle, name, enn_api_ptr) \
enn_api_ptr->name = \
reinterpret_cast<name##_fn>(loadApiFunction(handle, #name, false)); \
Expand Down Expand Up @@ -38,6 +44,102 @@ EnnApi* EnnApi::getEnnApiInstance() {
return &enn_api;
}

namespace {

constexpr uint32_t kPerfConfigIdDefault = 0;

struct PerfConfig {
PerfModePreference mode;
uint32_t config_id;
};

// Primary source: ro.hardware. Falls back to ro.soc.model if unavailable.
std::string getHwName() {
char prop_value[PROP_VALUE_MAX] = {};
if (__system_property_get("ro.hardware", prop_value) > 0) {
return std::string(prop_value);
}
return "";
}

std::string getSocName() {
char prop_value[PROP_VALUE_MAX] = {};
if (__system_property_get("ro.soc.model", prop_value) > 0) {
return std::string(prop_value);
}
return "";
}

// Extracts trailing digits, e.g. "exynos9955" -> "9955", "s5e9965" -> "9965".
bool trimToTrailingDigits(std::string& value) {
const char* digits = "0123456789";
auto last = value.find_last_of(digits);
if (last == std::string::npos) {
return false;
}
auto first = last;
while (first > 0 && std::strchr(digits, value[first - 1]) != nullptr) {
first--;
}
value = value.substr(first, last - first + 1);
return true;
}

const std::unordered_map<std::string, PerfConfig>& getSocPerfConfigMap() {
static const std::unordered_map<std::string, PerfConfig> kSocPerfConfig = {
{"9955", {ENN_PREF_MODE_PERFORMANCE, kPerfConfigIdDefault}},
{"9965", {ENN_PREF_MODE_CUSTOM, 100111}},
};
return kSocPerfConfig;
}

PerfConfig getPerfConfigForSoc() {
std::string key = getHwName();
if (key.empty()) {
key = getSocName();
}
if (!key.empty()) {
trimToTrailingDigits(key);
}

const auto& map = getSocPerfConfigMap();
auto it = map.find(key);
if (it != map.end()) {
return it->second;
}
return {ENN_PREF_MODE_PERFORMANCE, kPerfConfigIdDefault};
}

// Mirrors LiteRT's litert::samsung::SetGenAiPerfConfigFromSoc: detect the
// SoC from Android system properties and apply its known-good perf mode,
// instead of leaving the ENN runtime on its own default.
void setPerfConfigFromSoc(const EnnApi* enn_api) {
PerfConfig config = getPerfConfigForSoc();
if (enn_api->EnnSetPreferencePerfMode(static_cast<uint32_t>(config.mode)) !=
ENN_RET_SUCCESS) {
ENN_LOG_ERROR("Failed to set ENN preference perf mode.");
return;
}
if (config.config_id == kPerfConfigIdDefault) {
return;
}
if (enn_api->EnnSetPreferencePerfConfigId == nullptr ||
enn_api->EnnSetPreferencePerfConfigId(config.config_id) !=
ENN_RET_SUCCESS) {
ENN_LOG_WARN(
"Failed to set ENN perf config id %u, falling back to PERFORMANCE mode.",
config.config_id);
enn_api->EnnSetPreferencePerfMode(
static_cast<uint32_t>(ENN_PREF_MODE_PERFORMANCE));
}
}

} // namespace

void EnnApi::applyPerfConfigFromSoc() const {
setPerfConfigFromSoc(this);
}

EnnApi::EnnApi() {
auto status = loadApiLib();
if (status != Error::Ok) {
Expand Down Expand Up @@ -96,7 +198,13 @@ Error EnnApi::loadApiLib() {
ENN_LOAD_API_FUNC(
libenn_public_api_, EnnGetFileDescriptorFromEnnBuffer, this);
ENN_LOAD_API_FUNC(libenn_public_api_, EnnOpenModelFromFd, this);

// Optional: only newer ENN releases export these.
EnnSetPreferencePerfConfigId =
reinterpret_cast<EnnSetPreferencePerfConfigId_fn>(loadApiFunction(
libenn_public_api_, "EnnSetPreferencePerfConfigId", true));
EnnOpenModelFromFdWithWeight =
reinterpret_cast<EnnOpenModelFromFdWithWeight_fn>(loadApiFunction(
libenn_public_api_, "EnnOpenModelFromFdWithWeight", true));
return Error::Ok;
}

Expand Down
22 changes: 22 additions & 0 deletions backends/samsung/runtime/enn_api_implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,29 @@ class EnnApi {
static EnnApi* getEnnApiInstance();
bool isInitialized() const;

// Detects the SoC and applies its known-good ENN perf mode/config id.
// Must be called on the same thread that is about to open a model, and
// as the last preference-mutating call before that open, since
// EnnInitialize() resets the calling thread's preference on every call.
void applyPerfConfigFromSoc() const;

EnnReturn (*EnnInitialize)(void);
EnnReturn (*EnnSetPreferencePerfMode)(const uint32_t val);
EnnReturn (*EnnGetPreferencePerfMode)(uint32_t* val_ptr);
EnnReturn (*EnnSetPreferencePerfConfigId)(uint32_t val);
EnnReturn (*EnnOpenModel)(const char* model_file, EnnModelId* model_id);
EnnReturn (*EnnOpenModelFromMemory)(
const char* va,
const uint32_t size,
EnnModelId* model_id);
EnnReturn (*EnnOpenModelFromFd)(int _fd, EnnModelId* model_id);
EnnReturn (*EnnOpenModelFromFdWithWeight)(
const int fd,
const uint32_t size,
const uint32_t offset,
EnnBufferPtr* weights,
uint32_t n_weights,
EnnModelId* model_id);
EnnReturn (*EnnSetFastIpc)(void);
EnnReturn (*EnnUnsetFastIpc)(void);
EnnReturn (*EnnExecuteModelFastIpc)(
Expand Down Expand Up @@ -92,6 +106,7 @@ class EnnApi {
typedef EnnReturn (*EnnInitialize_fn)(void);
typedef EnnReturn (*EnnSetPreferencePerfMode_fn)(const uint32_t val);
typedef EnnReturn (*EnnGetPreferencePerfMode_fn)(uint32_t* val_ptr);
typedef EnnReturn (*EnnSetPreferencePerfConfigId_fn)(uint32_t val);
typedef EnnReturn (
*EnnOpenModel_fn)(const char* model_file, EnnModelId* model_id);
typedef EnnReturn (*EnnOpenModelFromMemory_fn)(
Expand Down Expand Up @@ -136,6 +151,13 @@ typedef EnnReturn (*EnnReleaseBuffer_fn)(EnnBufferPtr buf);
typedef EnnReturn (
*EnnGetFileDescriptorFromEnnBuffer_fn)(EnnBufferPtr buffer, int32_t* fd);
typedef EnnReturn (*EnnOpenModelFromFd_fn)(int _fd, EnnModelId* model_id);
typedef EnnReturn (*EnnOpenModelFromFdWithWeight_fn)(
const int fd,
const uint32_t size,
const uint32_t offset,
EnnBufferPtr* weights,
uint32_t n_weights,
EnnModelId* model_id);

} // namespace enn
} // namespace executor
Expand Down
Loading
Loading