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