Home | History | Annotate | Download | only in Renderscript
      1 /*
      2  * Copyright 2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #include "bcc/Renderscript/RSInfo.h"
     19 
     20 #if !defined(_WIN32)  /* TODO create a HAVE_DLFCN_H */
     21 #include <dlfcn.h>
     22 #endif
     23 
     24 #include <cstring>
     25 #include <new>
     26 #include <string>
     27 
     28 #include "bcc/Support/FileBase.h"
     29 #include "bcc/Support/Log.h"
     30 
     31 #ifdef HAVE_ANDROID_OS
     32 #include <cutils/properties.h>
     33 #endif
     34 
     35 using namespace bcc;
     36 
     37 const char RSInfo::LibBCCPath[] = "/system/lib/libbcc.so";
     38 const char RSInfo::LibCompilerRTPath[] = "/system/lib/libcompiler_rt.so";
     39 const char RSInfo::LibRSPath[] = "/system/lib/libRS.so";
     40 const char RSInfo::LibCLCorePath[] = "/system/lib/libclcore.bc";
     41 const char RSInfo::LibCLCoreDebugPath[] = "/system/lib/libclcore_debug.bc";
     42 #if defined(ARCH_X86_HAVE_SSE2)
     43 const char RSInfo::LibCLCoreX86Path[] = "/system/lib/libclcore_x86.bc";
     44 #endif
     45 #if defined(ARCH_ARM_HAVE_NEON)
     46 const char RSInfo::LibCLCoreNEONPath[] = "/system/lib/libclcore_neon.bc";
     47 #endif
     48 
     49 const uint8_t *RSInfo::LibBCCSHA1 = NULL;
     50 const uint8_t *RSInfo::LibCompilerRTSHA1 = NULL;
     51 const uint8_t *RSInfo::LibRSSHA1 = NULL;
     52 const uint8_t *RSInfo::LibCLCoreSHA1 = NULL;
     53 const uint8_t *RSInfo::LibCLCoreDebugSHA1 = NULL;
     54 #if defined(ARCH_ARM_HAVE_NEON)
     55 const uint8_t *RSInfo::LibCLCoreNEONSHA1 = NULL;
     56 #endif
     57 
     58 bool RSInfo::LoadBuiltInSHA1Information() {
     59 #ifdef TARGET_BUILD
     60   if (LibBCCSHA1 != NULL) {
     61     // Loaded before.
     62     return true;
     63   }
     64 
     65   void *h = ::dlopen("/system/lib/libbcc.sha1.so", RTLD_LAZY | RTLD_NOW);
     66   if (h == NULL) {
     67     ALOGE("Failed to load SHA-1 information from shared library '"
     68           "/system/lib/libbcc.sha1.so'! (%s)", ::dlerror());
     69     return false;
     70   }
     71 
     72   LibBCCSHA1 = reinterpret_cast<const uint8_t *>(::dlsym(h, "libbcc_so_SHA1"));
     73   LibCompilerRTSHA1 =
     74       reinterpret_cast<const uint8_t *>(::dlsym(h, "libcompiler_rt_so_SHA1"));
     75   LibRSSHA1 = reinterpret_cast<const uint8_t *>(::dlsym(h, "libRS_so_SHA1"));
     76   LibCLCoreSHA1 =
     77       reinterpret_cast<const uint8_t *>(::dlsym(h, "libclcore_bc_SHA1"));
     78   LibCLCoreDebugSHA1 =
     79       reinterpret_cast<const uint8_t *>(::dlsym(h, "libclcore_debug_bc_SHA1"));
     80 #if defined(ARCH_ARM_HAVE_NEON)
     81   LibCLCoreNEONSHA1 =
     82       reinterpret_cast<const uint8_t *>(::dlsym(h, "libclcore_neon_bc_SHA1"));
     83 #endif
     84 
     85   return true;
     86 #else  // TARGET_BUILD
     87   return false;
     88 #endif  // TARGET_BUILD
     89 }
     90 
     91 android::String8 RSInfo::GetPath(const char *pFilename) {
     92   android::String8 result(pFilename);
     93   result.append(".info");
     94   return result;
     95 }
     96 
     97 #define PRINT_DEPENDENCY(PREFIX, N, X) \
     98         ALOGV("\t" PREFIX "Source name: %s, "                                 \
     99                           "SHA-1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"   \
    100                                  "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",  \
    101               (N), (X)[ 0], (X)[ 1], (X)[ 2], (X)[ 3], (X)[ 4], (X)[ 5],      \
    102                    (X)[ 6], (X)[ 7], (X)[ 8], (X)[ 9], (X)[10], (X)[11],      \
    103                    (X)[12], (X)[13], (X)[14], (X)[15], (X)[16], (X)[17],      \
    104                    (X)[18], (X)[19]);
    105 
    106 bool RSInfo::CheckDependency(const RSInfo &pInfo,
    107                              const char *pInputFilename,
    108                              const DependencyTableTy &pDeps) {
    109   // Built-in dependencies are libbcc.so, libRS.so and libclcore.bc plus
    110   // libclcore_neon.bc if NEON is available on the target device.
    111 #if !defined(ARCH_ARM_HAVE_NEON)
    112   static const unsigned NumBuiltInDependencies = 5;
    113 #else
    114   static const unsigned NumBuiltInDependencies = 6;
    115 #endif
    116 
    117   LoadBuiltInSHA1Information();
    118 
    119   if (pInfo.mDependencyTable.size() != (pDeps.size() + NumBuiltInDependencies)) {
    120     ALOGD("Number of dependencies recorded mismatch (%lu v.s. %lu) in %s!",
    121           static_cast<unsigned long>(pInfo.mDependencyTable.size()),
    122           static_cast<unsigned long>(pDeps.size()), pInputFilename);
    123     return false;
    124   } else {
    125     // Built-in dependencies always go first.
    126     const std::pair<const char *, const uint8_t *> &cache_libbcc_dep =
    127         pInfo.mDependencyTable[0];
    128     const std::pair<const char *, const uint8_t *> &cache_libcompiler_rt_dep =
    129         pInfo.mDependencyTable[1];
    130     const std::pair<const char *, const uint8_t *> &cache_libRS_dep =
    131         pInfo.mDependencyTable[2];
    132     const std::pair<const char *, const uint8_t *> &cache_libclcore_dep =
    133         pInfo.mDependencyTable[3];
    134     const std::pair<const char *, const uint8_t *> &cache_libclcore_debug_dep =
    135         pInfo.mDependencyTable[4];
    136 #if defined(ARCH_ARM_HAVE_NEON)
    137     const std::pair<const char *, const uint8_t *> &cache_libclcore_neon_dep =
    138         pInfo.mDependencyTable[5];
    139 #endif
    140 
    141     // Check libbcc.so.
    142     if (::memcmp(cache_libbcc_dep.second, LibBCCSHA1, SHA1_DIGEST_LENGTH) != 0) {
    143         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    144               LibBCCPath);
    145         PRINT_DEPENDENCY("current - ", LibBCCPath, LibBCCSHA1);
    146         PRINT_DEPENDENCY("cache - ", cache_libbcc_dep.first,
    147                                      cache_libbcc_dep.second);
    148         return false;
    149     }
    150 
    151     // Check libcompiler_rt.so.
    152     if (::memcmp(cache_libcompiler_rt_dep.second, LibCompilerRTSHA1,
    153                  SHA1_DIGEST_LENGTH) != 0) {
    154         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    155               LibCompilerRTPath);
    156         PRINT_DEPENDENCY("current - ", LibCompilerRTPath, LibCompilerRTSHA1);
    157         PRINT_DEPENDENCY("cache - ", cache_libcompiler_rt_dep.first,
    158                                      cache_libcompiler_rt_dep.second);
    159         return false;
    160     }
    161 
    162     // Check libRS.so.
    163     if (::memcmp(cache_libRS_dep.second, LibRSSHA1, SHA1_DIGEST_LENGTH) != 0) {
    164         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    165               LibRSPath);
    166         PRINT_DEPENDENCY("current - ", LibRSPath, LibRSSHA1);
    167         PRINT_DEPENDENCY("cache - ", cache_libRS_dep.first,
    168                                      cache_libRS_dep.second);
    169         return false;
    170     }
    171 
    172     // Check libclcore.bc.
    173     if (::memcmp(cache_libclcore_dep.second, LibCLCoreSHA1,
    174                  SHA1_DIGEST_LENGTH) != 0) {
    175         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    176               LibCLCorePath);
    177         PRINT_DEPENDENCY("current - ", LibCLCorePath, LibCLCoreSHA1);
    178         PRINT_DEPENDENCY("cache - ", cache_libclcore_dep.first,
    179                                      cache_libclcore_dep.second);
    180         return false;
    181     }
    182 
    183     // Check libclcore_debug.bc.
    184     if (::memcmp(cache_libclcore_debug_dep.second, LibCLCoreDebugSHA1,
    185                  SHA1_DIGEST_LENGTH) != 0) {
    186         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    187               LibCLCoreDebugPath);
    188         PRINT_DEPENDENCY("current - ", LibCLCoreDebugPath, LibCLCoreDebugSHA1);
    189         PRINT_DEPENDENCY("cache - ", cache_libclcore_debug_dep.first,
    190                                      cache_libclcore_debug_dep.second);
    191         return false;
    192     }
    193 
    194 #if defined(ARCH_ARM_HAVE_NEON)
    195     // Check libclcore_neon.bc if NEON is available.
    196     if (::memcmp(cache_libclcore_neon_dep.second, LibCLCoreNEONSHA1,
    197                  SHA1_DIGEST_LENGTH) != 0) {
    198         ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
    199               LibCLCoreNEONPath);
    200         PRINT_DEPENDENCY("current - ", LibCLCoreNEONPath, LibCLCoreNEONSHA1);
    201         PRINT_DEPENDENCY("cache - ", cache_libclcore_neon_dep.first,
    202                                      cache_libclcore_neon_dep.second);
    203         return false;
    204     }
    205 #endif
    206 
    207     for (unsigned i = 0; i < pDeps.size(); i++) {
    208       const std::pair<const char *, const uint8_t *> &cache_dep =
    209           pInfo.mDependencyTable[i + NumBuiltInDependencies];
    210 
    211       if ((::strcmp(pDeps[i].first, cache_dep.first) != 0) ||
    212           (::memcmp(pDeps[i].second, cache_dep.second,
    213                     SHA1_DIGEST_LENGTH) != 0)) {
    214         ALOGD("Cache %s is dirty due to the source it dependends on has been "
    215               "changed:", pInputFilename);
    216         PRINT_DEPENDENCY("given - ", pDeps[i].first, pDeps[i].second);
    217         PRINT_DEPENDENCY("cache - ", cache_dep.first, cache_dep.second);
    218         return false;
    219       }
    220     }
    221   }
    222 
    223   return true;
    224 }
    225 
    226 RSInfo::RSInfo(size_t pStringPoolSize) : mStringPool(NULL) {
    227   ::memset(&mHeader, 0, sizeof(mHeader));
    228 
    229   ::memcpy(mHeader.magic, RSINFO_MAGIC, sizeof(mHeader.magic));
    230   ::memcpy(mHeader.version, RSINFO_VERSION, sizeof(mHeader.version));
    231 
    232   mHeader.headerSize = sizeof(mHeader);
    233 
    234   mHeader.dependencyTable.itemSize = sizeof(rsinfo::DependencyTableItem);
    235   mHeader.pragmaList.itemSize = sizeof(rsinfo::PragmaItem);
    236   mHeader.objectSlotList.itemSize = sizeof(rsinfo::ObjectSlotItem);
    237   mHeader.exportVarNameList.itemSize = sizeof(rsinfo::ExportVarNameItem);
    238   mHeader.exportFuncNameList.itemSize = sizeof(rsinfo::ExportFuncNameItem);
    239   mHeader.exportForeachFuncList.itemSize = sizeof(rsinfo::ExportForeachFuncItem);
    240 
    241   if (pStringPoolSize > 0) {
    242     mHeader.strPoolSize = pStringPoolSize;
    243     mStringPool = new (std::nothrow) char [ mHeader.strPoolSize ];
    244     if (mStringPool == NULL) {
    245       ALOGE("Out of memory when allocate memory for string pool in RSInfo "
    246             "constructor (size: %u)!", mHeader.strPoolSize);
    247     }
    248   }
    249 }
    250 
    251 RSInfo::~RSInfo() {
    252   delete [] mStringPool;
    253 }
    254 
    255 bool RSInfo::layout(off_t initial_offset) {
    256   mHeader.dependencyTable.offset = initial_offset +
    257                                    mHeader.headerSize +
    258                                    mHeader.strPoolSize;
    259   mHeader.dependencyTable.count = mDependencyTable.size();
    260 
    261 #define AFTER(_list) ((_list).offset + (_list).itemSize * (_list).count)
    262   mHeader.pragmaList.offset = AFTER(mHeader.dependencyTable);
    263   mHeader.pragmaList.count = mPragmas.size();
    264 
    265   mHeader.objectSlotList.offset = AFTER(mHeader.pragmaList);
    266   mHeader.objectSlotList.count = mObjectSlots.size();
    267 
    268   mHeader.exportVarNameList.offset = AFTER(mHeader.objectSlotList);
    269   mHeader.exportVarNameList.count = mExportVarNames.size();
    270 
    271   mHeader.exportFuncNameList.offset = AFTER(mHeader.exportVarNameList);
    272   mHeader.exportFuncNameList.count = mExportFuncNames.size();
    273 
    274   mHeader.exportForeachFuncList.offset = AFTER(mHeader.exportFuncNameList);
    275   mHeader.exportForeachFuncList.count = mExportForeachFuncs.size();
    276 #undef AFTER
    277 
    278   return true;
    279 }
    280 
    281 void RSInfo::dump() const {
    282   // Hide the codes to save the code size when debugging is disabled.
    283 #if !LOG_NDEBUG
    284 
    285   // Dump header
    286   ALOGV("RSInfo Header:");
    287   ALOGV("\tIs threadable: %s", ((mHeader.isThreadable) ? "true" : "false"));
    288   ALOGV("\tHeader size: %u", mHeader.headerSize);
    289   ALOGV("\tString pool size: %u", mHeader.strPoolSize);
    290 
    291 #define DUMP_LIST_HEADER(_name, _header) do { \
    292   ALOGV(_name ":"); \
    293   ALOGV("\toffset: %u", (_header).offset);  \
    294   ALOGV("\t# of item: %u", (_header).count);  \
    295   ALOGV("\tsize of each item: %u", (_header).itemSize); \
    296 } while (false)
    297   DUMP_LIST_HEADER("Dependency table", mHeader.dependencyTable);
    298   for (DependencyTableTy::const_iterator dep_iter = mDependencyTable.begin(),
    299           dep_end = mDependencyTable.end(); dep_iter != dep_end; dep_iter++) {
    300     PRINT_DEPENDENCY("", dep_iter->first, dep_iter->second);
    301   }
    302 
    303   DUMP_LIST_HEADER("Pragma list", mHeader.pragmaList);
    304   for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(),
    305         pragma_end = mPragmas.end(); pragma_iter != pragma_end; pragma_iter++) {
    306     ALOGV("\tkey: %s, value: %s", pragma_iter->first, pragma_iter->second);
    307   }
    308 
    309   DUMP_LIST_HEADER("RS object slots", mHeader.objectSlotList);
    310   for (ObjectSlotListTy::const_iterator slot_iter = mObjectSlots.begin(),
    311           slot_end = mObjectSlots.end(); slot_iter != slot_end; slot_iter++) {
    312     ALOGV("slot: %u", *slot_iter);
    313   }
    314 
    315   DUMP_LIST_HEADER("RS export variables", mHeader.exportVarNameList);
    316   for (ExportVarNameListTy::const_iterator var_iter = mExportVarNames.begin(),
    317           var_end = mExportVarNames.end(); var_iter != var_end; var_iter++) {
    318     ALOGV("name: %s", *var_iter);
    319   }
    320 
    321   DUMP_LIST_HEADER("RS export functions", mHeader.exportFuncNameList);
    322   for (ExportFuncNameListTy::const_iterator func_iter = mExportFuncNames.begin(),
    323         func_end = mExportFuncNames.end(); func_iter != func_end; func_iter++) {
    324     ALOGV("name: %s", *func_iter);
    325   }
    326 
    327   DUMP_LIST_HEADER("RS foreach list", mHeader.exportForeachFuncList);
    328   for (ExportForeachFuncListTy::const_iterator
    329           foreach_iter = mExportForeachFuncs.begin(),
    330           foreach_end = mExportForeachFuncs.end(); foreach_iter != foreach_end;
    331           foreach_iter++) {
    332     ALOGV("name: %s, signature: %05x", foreach_iter->first,
    333                                        foreach_iter->second);
    334   }
    335 #undef DUMP_LIST_HEADER
    336 
    337 #endif // LOG_NDEBUG
    338   return;
    339 }
    340 
    341 const char *RSInfo::getStringFromPool(rsinfo::StringIndexTy pStrIdx) const {
    342   // String pool uses direct indexing. Ensure that the pStrIdx is within the
    343   // range.
    344   if (pStrIdx >= mHeader.strPoolSize) {
    345     ALOGE("String index #%u is out of range in string pool (size: %u)!",
    346           pStrIdx, mHeader.strPoolSize);
    347     return NULL;
    348   }
    349   return &mStringPool[ pStrIdx ];
    350 }
    351 
    352 rsinfo::StringIndexTy RSInfo::getStringIdxInPool(const char *pStr) const {
    353   // Assume we are on the flat memory architecture (i.e., the memory space is
    354   // continuous.)
    355   if ((mStringPool + mHeader.strPoolSize) < pStr) {
    356     ALOGE("String %s does not in the string pool!", pStr);
    357     return rsinfo::gInvalidStringIndex;
    358   }
    359   return (pStr - mStringPool);
    360 }
    361 
    362 RSInfo::FloatPrecision RSInfo::getFloatPrecisionRequirement() const {
    363   // Check to see if we have any FP precision-related pragmas.
    364   std::string relaxed_pragma("rs_fp_relaxed");
    365   std::string imprecise_pragma("rs_fp_imprecise");
    366   std::string full_pragma("rs_fp_full");
    367   bool relaxed_pragma_seen = false;
    368   bool imprecise_pragma_seen = false;
    369   RSInfo::FloatPrecision result = FP_Full;
    370 
    371   for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(),
    372            pragma_end = mPragmas.end(); pragma_iter != pragma_end;
    373        pragma_iter++) {
    374     const char *pragma_key = pragma_iter->first;
    375     if (!relaxed_pragma.compare(pragma_key)) {
    376       if (relaxed_pragma_seen || imprecise_pragma_seen) {
    377         ALOGE("Multiple float precision pragmas specified!");
    378       }
    379       relaxed_pragma_seen = true;
    380     } else if (!imprecise_pragma.compare(pragma_key)) {
    381       if (relaxed_pragma_seen || imprecise_pragma_seen) {
    382         ALOGE("Multiple float precision pragmas specified!");
    383       }
    384       imprecise_pragma_seen = true;
    385     }
    386   }
    387 
    388   // Imprecise is selected over Relaxed precision.
    389   // In the absence of both, we stick to the default Full precision.
    390   if (imprecise_pragma_seen) {
    391     result = FP_Imprecise;
    392   } else if (relaxed_pragma_seen) {
    393     result = FP_Relaxed;
    394   }
    395 
    396 #ifdef HAVE_ANDROID_OS
    397   // Provide an override for precsion via adb shell setprop
    398   // adb shell setprop debug.rs.precision rs_fp_full
    399   // adb shell setprop debug.rs.precision rs_fp_relaxed
    400   // adb shell setprop debug.rs.precision rs_fp_imprecise
    401   char precision_prop_buf[PROPERTY_VALUE_MAX];
    402   property_get("debug.rs.precision", precision_prop_buf, "");
    403 
    404   if (precision_prop_buf[0]) {
    405     if (!relaxed_pragma.compare(precision_prop_buf)) {
    406       ALOGI("Switching to RS FP relaxed mode via setprop");
    407       result = FP_Relaxed;
    408     } else if (!imprecise_pragma.compare(precision_prop_buf)) {
    409       ALOGI("Switching to RS FP imprecise mode via setprop");
    410       result = FP_Imprecise;
    411     } else if (!full_pragma.compare(precision_prop_buf)) {
    412       ALOGI("Switching to RS FP full mode via setprop");
    413       result = FP_Full;
    414     }
    415   }
    416 #endif
    417 
    418   return result;
    419 }
    420