Home | History | Annotate | Download | only in nnapi
      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