blob: 006db1d45f2df0bedd4d5126ab857a5c0978578e [file] [edit]
/*
* Copyright (C) 2021 MediaTek Inc., this file is modified on 02/26/2021
* by MediaTek Inc. based on MIT License .
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the ""Software""), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "delegate/mtk_neuron/neuron_implementation.h"
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <string>
#include "common/minimal_logging.h"
#ifdef __ANDROID__
#include <android/dlext.h>
#include <android/log.h>
#include <sys/system_properties.h>
#endif // __ANDROID__
#define NEURONAPI_LOG(format, ...) \
TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO, format, ##__VA_ARGS__)
#define RETURN_NEURON_ERROR(code, call_desc) \
do { \
const auto _code = (code); \
const auto _call_desc = (call_desc); \
if (_code != 0) { \
NEURONAPI_LOG("Neuron returned error %d while %s.\n", _code, \
_call_desc); \
} \
} while (0)
/// M: NeuroPilot @}
void* LoadFunction(void* handle, const char* name, bool optional) {
if (handle == nullptr) {
return nullptr;
}
void* fn = dlsym(handle, name);
if (fn == nullptr && !optional) {
NEURONAPI_LOG("neuron error: unable to open function %s", name);
}
return fn;
}
#ifndef __ANDROID__
// Add /dev/shm implementation of shared memory for non-Android platforms
int ASharedMemory_create(const char* name, size_t size) {
int fd = shm_open(name, O_RDWR | O_CREAT, 0644);
if (fd < 0) {
return fd;
}
int result = ftruncate(fd, size);
if (result < 0) {
close(fd);
return -1;
}
return fd;
}
#endif // __ANDROID__
#define LOAD_FUNCTION(handle, name, neuronapi_obj) \
neuronapi_obj.name = reinterpret_cast<name##_fn>( \
LoadFunction(handle, #name, /*optional*/ false));
#define LOAD_FUNCTION_OPTIONAL(handle, name, neuronapi_obj) \
neuronapi_obj.name = reinterpret_cast<name##_fn>( \
LoadFunction(handle, #name, /*optional*/ true));
#define LOAD_FUNCTION_RENAME(handle, name, symbol, neuronapi_obj) \
neuronapi_obj.name = reinterpret_cast<name##_fn>( \
LoadFunction(handle, symbol, /*optional*/ false));
const NeuronApi LoadNeuronApi() {
const std::string libraries[] = {"libneuron_adapter.so"};
NeuronApi neuron_api = {};
neuron_api.android_sdk_version = 31;
void* libneuron_adapter = nullptr;
for (const auto& lib : libraries) {
libneuron_adapter = dlopen(lib.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (libneuron_adapter) {
NEURONAPI_LOG("dlopen %s", lib.c_str());
break;
}
}
neuron_api.handle = libneuron_adapter;
neuron_api.neuron_exists = libneuron_adapter != nullptr;
LOAD_FUNCTION(libneuron_adapter, Neuron_getVersion, neuron_api);
LOAD_FUNCTION(libneuron_adapter, Neuron_getL1MemorySizeKb, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_create, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_free, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_finish, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_getSupportedOperationsForDevices,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_getSupportedOperations,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_addOperand, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_setOperandValue, neuron_api);
LOAD_FUNCTION(libneuron_adapter,
NeuronModel_setOperandSymmPerChannelQuantParams, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_setOperandPerChannelQuantParams,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_addOperation, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_identifyInputsAndOutputs,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_relaxComputationFloat32toFloat16,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_create, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_create, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_setPreference, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_setPriority, neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter,
NeuronCompilation_getCompiledNetworkSize, neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter,
NeuronCompilation_getSupportedOperations, neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter,
NeuronCompilation_setOptimizationHint, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_free, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_finish, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_setCaching, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_setL1MemorySizeKb,
neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter,
NeuronCompilation_getOptimizationString, neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter,
NeuronCompilation_setOnlyAllowOptimizationString,
neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter, Neuron_getNeuroPilotMagicNumber,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_free, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_setInput, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_setInputFromMemory,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_setOutput, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_setOutputFromMemory,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_compute, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_startComputeWithDependencies,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_setBoostHint, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_getOutputOperandRank,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_getOutputOperandDimensions,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronExecution_setLoopTimeout, neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter, NeuronExecution_setCacheFlushHint,
neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter, NeuronExecution_setDeadline,
neuron_api);
LOAD_FUNCTION_OPTIONAL(libneuron_adapter, NeuronExecution_setAbortTime,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_setOptimizationString,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, Neuron_getDeviceCount, neuron_api);
LOAD_FUNCTION(libneuron_adapter, Neuron_getDevice, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronDevice_getName, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronCompilation_createForDevices,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronEvent_free, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronEvent_wait, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronEvent_createFromSyncFenceFd,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronEvent_getSyncFenceFd, neuron_api);
#if defined(__ANDROID__)
LOAD_FUNCTION(libneuron_adapter, NeuronMemory_createFromAHardwareBuffer,
neuron_api);
#endif
LOAD_FUNCTION(libneuron_adapter, NeuronMemory_createFromFd, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronMemory_free, neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronDevice_getExtensionSupport,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_getExtensionOperandType,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_getExtensionOperationType,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_addOperationExtension,
neuron_api);
LOAD_FUNCTION(libneuron_adapter, NeuronModel_setOperandExtensionData,
neuron_api);
uint32_t num_devices = 0;
if (libneuron_adapter != nullptr) {
neuron_api.Neuron_getDeviceCount(&num_devices);
}
if (num_devices == 0) {
neuron_api.neuron_exists = false;
} else if (neuron_api.neuron_exists) {
// check if mdla/dsp supported
neuron_api.neuron_exists = false;
for (uint32_t i = 0; i < num_devices; ++i) {
const char* name = nullptr;
NeuronDevice* device = nullptr;
RETURN_NEURON_ERROR(neuron_api.Neuron_getDevice(i, &device),
"getting device");
RETURN_NEURON_ERROR(neuron_api.NeuronDevice_getName(device, &name),
"getting device name");
TFLITE_LOG_PROD(tflite::TFLITE_LOG_VERBOSE, "Got device name: %s", name);
if (name != nullptr && (strncmp(name, "mtk-dsp", 7) == 0 ||
strncmp(name, "mtk-mdla", 8) == 0)) {
neuron_api.neuron_exists = true;
break;
}
}
}
if (!neuron_api.neuron_exists) {
NEURONAPI_LOG("neuron error: Neuron adapter API exists: %d",
neuron_api.neuron_exists);
}
// ASharedMemory_create has different implementations in Android depending on
// the partition. Generally it can be loaded from libandroid.so but in vendor
// partition (e.g. if a HAL wants to use Neuron) it is only accessible through
// libcutils.
#ifdef __ANDROID__
void* libandroid = nullptr;
libandroid = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
if (libandroid != nullptr) {
LOAD_FUNCTION(libandroid, ASharedMemory_create, neuron_api);
} else {
void* cutils_handle = dlopen("libcutils.so", RTLD_LAZY | RTLD_LOCAL);
if (cutils_handle != nullptr) {
LOAD_FUNCTION_RENAME(cutils_handle, ASharedMemory_create,
"ashmem_create_region", neuron_api);
} else {
NEURONAPI_LOG("neuron error: unable to open neither libraries %s and %s",
"libandroid.so", "libcutils.so");
}
}
#else
if (libneuron_adapter != nullptr) {
neuron_api.ASharedMemory_create = ASharedMemory_create;
}
#endif // __ANDROID__
return neuron_api;
}
const NeuronApi* NeuronApiImplementation() {
static const NeuronApi neuron_api = LoadNeuronApi();
if (neuron_api.neuron_exists) {
NeuronRuntimeVersion version;
if (neuron_api.Neuron_getVersion(&version) == NEURON_NO_ERROR) {
TFLITE_LOG_PROD_ONCE(
tflite::TFLITE_LOG_INFO, "NeuronApi version: %d.%d.%d",
static_cast<int>(version.major), static_cast<int>(version.minor),
static_cast<int>(version.patch));
} else {
NEURONAPI_LOG("NeuronApi error: fail to get version by %s",
"Neuron_getVersion");
}
}
return &neuron_api;
}