1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 #include "tensorflow/lite/nnapi/nnapi_implementation.h" 16 17 #include <dlfcn.h> 18 #include <fcntl.h> 19 #include <sys/mman.h> 20 #include <sys/stat.h> 21 #include <unistd.h> 22 23 #include <cstdlib> 24 25 #ifdef __ANDROID__ 26 #include <sys/system_properties.h> 27 #endif // __ANDROID__ 28 29 #define NNAPI_LOG(format, ...) fprintf(stderr, format "\n", __VA_ARGS__); 30 31 namespace { 32 33 #ifdef __ANDROID__ 34 int32_t GetAndroidSdkVersion() { 35 const char* sdkProp = "ro.build.version.sdk"; 36 char sdkVersion[PROP_VALUE_MAX]; 37 int length = __system_property_get(sdkProp, sdkVersion); 38 if (length != 0) { 39 int32_t result = 0; 40 for (int i = 0; i < length; ++i) { 41 int digit = sdkVersion[i] - '0'; 42 if (digit < 0 || digit > 9) { 43 // Non-numeric SDK version, assume it's higher than expected; 44 return 0xffff; 45 } 46 result = result * 10 + digit; 47 } 48 // TODO(levp): remove once SDK gets updated to 29th level 49 // Upgrade SDK version for pre-release Q to be able to test functionality 50 // available from SDK level 29. 51 if (result == 28) { 52 char versionCodename[PROP_VALUE_MAX]; 53 const char* versionCodenameProp = "ro.build.version.codename"; 54 length = __system_property_get(versionCodenameProp, versionCodename); 55 if (length != 0) { 56 if (versionCodename[0] == 'Q') { 57 return 29; 58 } 59 } 60 } 61 return result; 62 } 63 return 0; 64 } 65 #endif // __ANDROID__ 66 67 void* LoadFunction(void* handle, const char* name, bool optional) { 68 if (handle == nullptr) { 69 return nullptr; 70 } 71 void* fn = dlsym(handle, name); 72 if (fn == nullptr && !optional) { 73 NNAPI_LOG("nnapi error: unable to open function %s", name); 74 } 75 return fn; 76 } 77 78 #ifndef __ANDROID__ 79 // Add /dev/shm implementation of shared memory for non-Android platforms 80 int ASharedMemory_create(const char* name, size_t size) { 81 int fd = shm_open(name, O_RDWR | O_CREAT, 0644); 82 if (fd < 0) { 83 return fd; 84 } 85 int result = ftruncate(fd, size); 86 if (result < 0) { 87 close(fd); 88 return -1; 89 } 90 return fd; 91 } 92 #endif // __ANDROID__ 93 94 #define LOAD_FUNCTION(handle, name) \ 95 nnapi.name = reinterpret_cast<name##_fn>( \ 96 LoadFunction(handle, #name, /*optional*/ false)); 97 98 #define LOAD_FUNCTION_OPTIONAL(handle, name) \ 99 nnapi.name = reinterpret_cast<name##_fn>( \ 100 LoadFunction(handle, #name, /*optional*/ true)); 101 102 const NnApi LoadNnApi() { 103 NnApi nnapi = {}; 104 nnapi.android_sdk_version = 0; 105 106 #ifdef __ANDROID__ 107 void* libandroid = nullptr; 108 nnapi.android_sdk_version = GetAndroidSdkVersion(); 109 if (nnapi.android_sdk_version < 27) { 110 NNAPI_LOG("nnapi error: requires android sdk version to be at least %d", 111 27); 112 nnapi.nnapi_exists = false; 113 return nnapi; 114 } 115 libandroid = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL); 116 if (libandroid == nullptr) { 117 NNAPI_LOG("nnapi error: unable to open library %s", "libandroid.so"); 118 } 119 #endif // __ANDROID__ 120 121 void* libneuralnetworks = nullptr; 122 // TODO(b/123243014): change RTLD_LOCAL? Assumes there can be multiple 123 // instances of nn api RT 124 libneuralnetworks = dlopen("libneuralnetworks.so", RTLD_LAZY | RTLD_LOCAL); 125 if (libneuralnetworks == nullptr) { 126 NNAPI_LOG("nnapi error: unable to open library %s", "libneuralnetworks.so"); 127 } 128 129 nnapi.nnapi_exists = libneuralnetworks != nullptr; 130 131 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksMemory_createFromFd); 132 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksMemory_free); 133 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_create); 134 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_free); 135 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_finish); 136 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_addOperand); 137 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_setOperandValue); 138 LOAD_FUNCTION_OPTIONAL( 139 libneuralnetworks, 140 ANeuralNetworksModel_setOperandSymmPerChannelQuantParams); 141 LOAD_FUNCTION(libneuralnetworks, 142 ANeuralNetworksModel_setOperandValueFromMemory); 143 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksModel_addOperation); 144 LOAD_FUNCTION(libneuralnetworks, 145 ANeuralNetworksModel_identifyInputsAndOutputs); 146 LOAD_FUNCTION(libneuralnetworks, 147 ANeuralNetworksModel_relaxComputationFloat32toFloat16); 148 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_create); 149 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_free); 150 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_setPreference); 151 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksCompilation_finish); 152 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_create); 153 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_free); 154 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_setInput); 155 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_setInputFromMemory); 156 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_setOutput); 157 LOAD_FUNCTION(libneuralnetworks, 158 ANeuralNetworksExecution_setOutputFromMemory); 159 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksExecution_startCompute); 160 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksEvent_wait); 161 LOAD_FUNCTION(libneuralnetworks, ANeuralNetworksEvent_free); 162 #ifdef __ANDROID__ 163 LOAD_FUNCTION(libandroid, ASharedMemory_create); 164 #else 165 nnapi.ASharedMemory_create = ASharedMemory_create; 166 #endif // __ANDROID__ 167 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworks_getDeviceCount); 168 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworks_getDevice); 169 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksDevice_getName); 170 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksDevice_getVersion); 171 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 172 ANeuralNetworksDevice_getFeatureLevel); 173 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksDevice_getType); 174 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 175 ANeuralNetworksModel_getSupportedOperationsForDevices); 176 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 177 ANeuralNetworksCompilation_createForDevices); 178 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 179 ANeuralNetworksCompilation_setCaching); 180 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksExecution_compute); 181 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 182 ANeuralNetworksExecution_getOutputOperandRank); 183 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 184 ANeuralNetworksExecution_getOutputOperandDimensions); 185 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksBurst_create); 186 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, ANeuralNetworksBurst_free); 187 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 188 ANeuralNetworksExecution_burstCompute); 189 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 190 ANeuralNetworksMemory_createFromAHardwareBuffer); 191 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 192 ANeuralNetworksExecution_setMeasureTiming); 193 LOAD_FUNCTION_OPTIONAL(libneuralnetworks, 194 ANeuralNetworksExecution_getDuration); 195 return nnapi; 196 } 197 198 } // namespace 199 200 const NnApi* NnApiImplementation() { 201 static const NnApi nnapi = LoadNnApi(); 202 return &nnapi; 203 } 204