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