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 android::String8 RSInfo::GetPath(const char *pFilename) { 38 android::String8 result(pFilename); 39 result.append(".info"); 40 return result; 41 } 42 43 static std::string stringFromSourceHash(const RSInfo::DependencyHashTy& hash) { 44 std::string s; 45 s.reserve(SHA1_DIGEST_LENGTH + 1); 46 for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) { 47 char buf[4]; 48 snprintf(buf, sizeof(buf), "%02x", hash[i]); 49 s.append(buf); 50 } 51 return s; 52 } 53 54 std::string bcc::getCommandLine(int argc, const char* const* argv) { 55 std::string s; 56 for (int i = 0; i < argc; i++) { 57 if (i > 0) { 58 s += ' '; 59 } 60 s += argv[i]; 61 } 62 return s; 63 } 64 65 bool RSInfo::IsConsistent(const char* pInputFilename, const DependencyHashTy& expectedSourceHash, 66 const char* expectedCompileCommandLine, 67 const char* expectedBuildFingerprint) { 68 if (::memcmp(mSourceHash, expectedSourceHash, SHA1_DIGEST_LENGTH) != 0) { 69 ALOGD("Cache %s is dirty due to the source it depends on has been changed:", 70 pInputFilename); 71 ALOGD("expected: %s", stringFromSourceHash(expectedSourceHash).c_str()); 72 ALOGD("cached : %s", stringFromSourceHash(mSourceHash).c_str()); 73 return false; 74 } 75 if (strcmp(expectedCompileCommandLine, mCompileCommandLine) != 0) { 76 ALOGD("Cache %s is dirty because the command line used to compile it has changed:", 77 pInputFilename); 78 ALOGD("expected: %s", expectedCompileCommandLine); 79 ALOGD("cached : %s", mCompileCommandLine); 80 return false; 81 } 82 if (strcmp(expectedBuildFingerprint, mBuildFingerprint) != 0) { 83 ALOGD("Cache %s is dirty because the build fingerprint has changed:", pInputFilename); 84 ALOGD("expected: %s", expectedBuildFingerprint); 85 ALOGD("cached : %s", mBuildFingerprint); 86 return false; 87 } 88 return true; 89 } 90 91 RSInfo::RSInfo(size_t pStringPoolSize) : mStringPool(NULL) { 92 ::memset(&mHeader, 0, sizeof(mHeader)); 93 94 ::memcpy(mHeader.magic, RSINFO_MAGIC, sizeof(mHeader.magic)); 95 ::memcpy(mHeader.version, RSINFO_VERSION, sizeof(mHeader.version)); 96 97 mHeader.headerSize = sizeof(mHeader); 98 99 mHeader.pragmaList.itemSize = sizeof(rsinfo::PragmaItem); 100 mHeader.objectSlotList.itemSize = sizeof(rsinfo::ObjectSlotItem); 101 mHeader.exportVarNameList.itemSize = sizeof(rsinfo::ExportVarNameItem); 102 mHeader.exportFuncNameList.itemSize = sizeof(rsinfo::ExportFuncNameItem); 103 mHeader.exportForeachFuncList.itemSize = sizeof(rsinfo::ExportForeachFuncItem); 104 105 if (pStringPoolSize > 0) { 106 mHeader.strPoolSize = pStringPoolSize; 107 mStringPool = new (std::nothrow) char [ mHeader.strPoolSize ]; 108 if (mStringPool == NULL) { 109 ALOGE("Out of memory when allocate memory for string pool in RSInfo " 110 "constructor (size: %u)!", mHeader.strPoolSize); 111 } 112 ::memset(mStringPool, 0, mHeader.strPoolSize); 113 } 114 mSourceHash = NULL; 115 mCompileCommandLine = NULL; 116 mBuildFingerprint = NULL; 117 } 118 119 RSInfo::~RSInfo() { 120 delete [] mStringPool; 121 } 122 123 bool RSInfo::layout(off_t initial_offset) { 124 mHeader.pragmaList.offset = initial_offset + 125 mHeader.headerSize + 126 mHeader.strPoolSize; 127 mHeader.pragmaList.count = mPragmas.size(); 128 129 #define AFTER(_list) ((_list).offset + (_list).itemSize * (_list).count) 130 mHeader.objectSlotList.offset = AFTER(mHeader.pragmaList); 131 mHeader.objectSlotList.count = mObjectSlots.size(); 132 133 mHeader.exportVarNameList.offset = AFTER(mHeader.objectSlotList); 134 mHeader.exportVarNameList.count = mExportVarNames.size(); 135 136 mHeader.exportFuncNameList.offset = AFTER(mHeader.exportVarNameList); 137 mHeader.exportFuncNameList.count = mExportFuncNames.size(); 138 139 mHeader.exportForeachFuncList.offset = AFTER(mHeader.exportFuncNameList); 140 mHeader.exportForeachFuncList.count = mExportForeachFuncs.size(); 141 #undef AFTER 142 143 return true; 144 } 145 146 void RSInfo::dump() const { 147 // Hide the codes to save the code size when debugging is disabled. 148 #if !LOG_NDEBUG 149 150 // Dump header 151 ALOGV("RSInfo Header:"); 152 ALOGV("\tIs threadable: %s", ((mHeader.isThreadable) ? "true" : "false")); 153 ALOGV("\tHeader size: %u", mHeader.headerSize); 154 ALOGV("\tString pool size: %u", mHeader.strPoolSize); 155 156 if (mSourceHash == NULL) { 157 ALOGV("Source hash: NULL!"); 158 } else { 159 ALOGV("Source hash: %s", stringFromSourceHash(mSourceHash).c_str()); 160 } 161 162 ALOGV("Compile Command Line: ", mCompileCommandLine ? mCompileCommandLine : "(NULL)"); 163 ALOGV("mBuildFingerprint: ", mBuildFingerprint ? mBuildFingerprint : "(NULL)"); 164 165 #define DUMP_LIST_HEADER(_name, _header) do { \ 166 ALOGV(_name ":"); \ 167 ALOGV("\toffset: %u", (_header).offset); \ 168 ALOGV("\t# of item: %u", (_header).count); \ 169 ALOGV("\tsize of each item: %u", (_header).itemSize); \ 170 } while (false) 171 172 DUMP_LIST_HEADER("Pragma list", mHeader.pragmaList); 173 for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(), 174 pragma_end = mPragmas.end(); pragma_iter != pragma_end; pragma_iter++) { 175 ALOGV("\tkey: %s, value: %s", pragma_iter->first, pragma_iter->second); 176 } 177 178 DUMP_LIST_HEADER("RS object slots", mHeader.objectSlotList); 179 for (ObjectSlotListTy::const_iterator slot_iter = mObjectSlots.begin(), 180 slot_end = mObjectSlots.end(); slot_iter != slot_end; slot_iter++) { 181 ALOGV("slot: %u", *slot_iter); 182 } 183 184 DUMP_LIST_HEADER("RS export variables", mHeader.exportVarNameList); 185 for (ExportVarNameListTy::const_iterator var_iter = mExportVarNames.begin(), 186 var_end = mExportVarNames.end(); var_iter != var_end; var_iter++) { 187 ALOGV("name: %s", *var_iter); 188 } 189 190 DUMP_LIST_HEADER("RS export functions", mHeader.exportFuncNameList); 191 for (ExportFuncNameListTy::const_iterator func_iter = mExportFuncNames.begin(), 192 func_end = mExportFuncNames.end(); func_iter != func_end; func_iter++) { 193 ALOGV("name: %s", *func_iter); 194 } 195 196 DUMP_LIST_HEADER("RS foreach list", mHeader.exportForeachFuncList); 197 for (ExportForeachFuncListTy::const_iterator 198 foreach_iter = mExportForeachFuncs.begin(), 199 foreach_end = mExportForeachFuncs.end(); foreach_iter != foreach_end; 200 foreach_iter++) { 201 ALOGV("name: %s, signature: %05x", foreach_iter->first, 202 foreach_iter->second); 203 } 204 #undef DUMP_LIST_HEADER 205 206 #endif // LOG_NDEBUG 207 return; 208 } 209 210 const char *RSInfo::getStringFromPool(rsinfo::StringIndexTy pStrIdx) const { 211 // String pool uses direct indexing. Ensure that the pStrIdx is within the 212 // range. 213 if (pStrIdx >= mHeader.strPoolSize) { 214 ALOGE("String index #%u is out of range in string pool (size: %u)!", 215 pStrIdx, mHeader.strPoolSize); 216 return NULL; 217 } 218 return &mStringPool[ pStrIdx ]; 219 } 220 221 rsinfo::StringIndexTy RSInfo::getStringIdxInPool(const char *pStr) const { 222 // Assume we are on the flat memory architecture (i.e., the memory space is 223 // continuous.) 224 if ((mStringPool + mHeader.strPoolSize) < pStr) { 225 ALOGE("String %s does not in the string pool!", pStr); 226 return rsinfo::gInvalidStringIndex; 227 } 228 return (pStr - mStringPool); 229 } 230 231 RSInfo::FloatPrecision RSInfo::getFloatPrecisionRequirement() const { 232 // Check to see if we have any FP precision-related pragmas. 233 std::string relaxed_pragma("rs_fp_relaxed"); 234 std::string imprecise_pragma("rs_fp_imprecise"); 235 std::string full_pragma("rs_fp_full"); 236 bool relaxed_pragma_seen = false; 237 bool full_pragma_seen = false; 238 239 for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(), 240 pragma_end = mPragmas.end(); pragma_iter != pragma_end; 241 pragma_iter++) { 242 const char *pragma_key = pragma_iter->first; 243 if (!relaxed_pragma.compare(pragma_key)) { 244 relaxed_pragma_seen = true; 245 } else if (!imprecise_pragma.compare(pragma_key)) { 246 ALOGW("rs_fp_imprecise is deprecated. Assuming rs_fp_relaxed instead."); 247 relaxed_pragma_seen = true; 248 } else if (!full_pragma.compare(pragma_key)) { 249 full_pragma_seen = true; 250 } 251 } 252 253 if (relaxed_pragma_seen && full_pragma_seen) { 254 ALOGE("Full and relaxed precision specified at the same time!"); 255 } 256 RSInfo::FloatPrecision result = relaxed_pragma_seen ? FP_Relaxed : FP_Full; 257 258 #ifdef HAVE_ANDROID_OS 259 // Provide an override for precsion via adb shell setprop 260 // adb shell setprop debug.rs.precision rs_fp_full 261 // adb shell setprop debug.rs.precision rs_fp_relaxed 262 // adb shell setprop debug.rs.precision rs_fp_imprecise 263 char precision_prop_buf[PROPERTY_VALUE_MAX]; 264 property_get("debug.rs.precision", precision_prop_buf, ""); 265 266 if (precision_prop_buf[0]) { 267 if (!relaxed_pragma.compare(precision_prop_buf)) { 268 ALOGI("Switching to RS FP relaxed mode via setprop"); 269 result = FP_Relaxed; 270 } else if (!imprecise_pragma.compare(precision_prop_buf)) { 271 ALOGW("Switching to RS FP relaxed mode via setprop. rs_fp_imprecise was specified but is " 272 "deprecated "); 273 result = FP_Relaxed; 274 } else if (!full_pragma.compare(precision_prop_buf)) { 275 ALOGI("Switching to RS FP full mode via setprop"); 276 result = FP_Full; 277 } else { 278 ALOGE("Unrecognized debug.rs.precision %s", precision_prop_buf); 279 } 280 } 281 #endif 282 283 return result; 284 } 285