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