RSCompilerDriver.cpp revision 86a0b797c221d4c3373dc10c8229b75b6747f6e7
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#include "bcc/Renderscript/RSCompilerDriver.h"
18
19#include <llvm/Support/Path.h>
20
21#include "bcinfo/BitcodeWrapper.h"
22
23#include "bcc/Renderscript/RSExecutable.h"
24#include "bcc/Renderscript/RSScript.h"
25#include "bcc/Support/CompilerConfig.h"
26#include "bcc/Support/TargetCompilerConfigs.h"
27#include "bcc/Source.h"
28#include "bcc/Support/FileMutex.h"
29#include "bcc/Support/Log.h"
30#include "bcc/Support/InputFile.h"
31#include "bcc/Support/Initialization.h"
32#include "bcc/Support/Sha1Util.h"
33#include "bcc/Support/OutputFile.h"
34
35#include <cutils/properties.h>
36#include <utils/String8.h>
37#include <utils/StopWatch.h>
38
39using namespace bcc;
40
41namespace {
42
43bool is_force_recompile() {
44  char buf[PROPERTY_VALUE_MAX];
45
46  // Re-compile if floating point precision has been overridden.
47  property_get("debug.rs.precision", buf, "");
48  if (buf[0] != '\0') {
49    return true;
50  }
51
52  // Re-compile if debug.rs.forcerecompile is set.
53  property_get("debug.rs.forcerecompile", buf, "0");
54  if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
55    return true;
56  } else {
57    return false;
58  }
59}
60
61} // end anonymous namespace
62
63RSCompilerDriver::RSCompilerDriver() : mConfig(NULL), mCompiler() {
64  init::Initialize();
65  // Chain the symbol resolvers for BCC runtimes and RS runtimes.
66  mResolver.chainResolver(mBCCRuntime);
67  mResolver.chainResolver(mRSRuntime);
68}
69
70RSCompilerDriver::~RSCompilerDriver() {
71  delete mConfig;
72}
73
74RSExecutable *
75RSCompilerDriver::loadScriptCache(const char *pOutputPath,
76                                  const RSInfo::DependencyTableTy &pDeps) {
77  android::StopWatch load_time("bcc: RSCompilerDriver::loadScriptCache time");
78  RSExecutable *result = NULL;
79
80  if (is_force_recompile())
81    return NULL;
82
83  //===--------------------------------------------------------------------===//
84  // Acquire the read lock for reading output object file.
85  //===--------------------------------------------------------------------===//
86  FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath);
87
88  if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
89    ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath,
90          read_output_mutex.getErrorMessage().c_str());
91    return NULL;
92  }
93
94  //===--------------------------------------------------------------------===//
95  // Read the output object file.
96  //===--------------------------------------------------------------------===//
97  InputFile *output_file = new (std::nothrow) InputFile(pOutputPath);
98
99  if ((output_file == NULL) || output_file->hasError()) {
100    ALOGE("Unable to open the %s for read! (%s)", pOutputPath,
101          output_file->getErrorMessage().c_str());
102    delete output_file;
103    return NULL;
104  }
105
106  //===--------------------------------------------------------------------===//
107  // Acquire the read lock on output_file for reading its RS info file.
108  //===--------------------------------------------------------------------===//
109  android::String8 info_path = RSInfo::GetPath(*output_file);
110
111  if (!output_file->lock()) {
112    ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
113          pOutputPath, info_path.string(),
114          output_file->getErrorMessage().c_str());
115    delete output_file;
116    return NULL;
117  }
118
119 //===---------------------------------------------------------------------===//
120  // Open and load the RS info file.
121  //===--------------------------------------------------------------------===//
122  InputFile info_file(info_path.string());
123  RSInfo *info = RSInfo::ReadFromFile(info_file, pDeps);
124
125  // Release the lock on output_file.
126  output_file->unlock();
127
128  if (info == NULL) {
129    delete output_file;
130    return NULL;
131  }
132
133  //===--------------------------------------------------------------------===//
134  // Create the RSExecutable.
135  //===--------------------------------------------------------------------===//
136  result = RSExecutable::Create(*info, *output_file, mResolver);
137  if (result == NULL) {
138    delete output_file;
139    delete info;
140    return NULL;
141  }
142
143  return result;
144}
145
146bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
147  bool changed = false;
148
149  const llvm::CodeGenOpt::Level script_opt_level =
150      static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
151
152  if (mConfig != NULL) {
153    // Renderscript bitcode may have their optimization flag configuration
154    // different than the previous run of RS compilation.
155    if (mConfig->getOptimizationLevel() != script_opt_level) {
156      mConfig->setOptimizationLevel(script_opt_level);
157      changed = true;
158    }
159  } else {
160    // Haven't run the compiler ever.
161    mConfig = new (std::nothrow) DefaultCompilerConfig();
162    if (mConfig == NULL) {
163      // Return false since mConfig remains NULL and out-of-memory.
164      return false;
165    }
166    mConfig->setOptimizationLevel(script_opt_level);
167    changed = true;
168  }
169
170#if defined(DEFAULT_ARM_CODEGEN)
171  // NEON should be disable when full-precision floating point is required.
172  assert((pScript.getInfo() != NULL) && "NULL RS info!");
173  if (pScript.getInfo()->getFloatPrecisionRequirement() == RSInfo::FP_Full) {
174    // Must be ARMCompilerConfig.
175    ARMCompilerConfig *arm_config = static_cast<ARMCompilerConfig *>(mConfig);
176    changed |= arm_config->enableNEON(/* pEnable */false);
177  }
178#endif
179
180  return changed;
181}
182
183RSExecutable *
184RSCompilerDriver::compileScript(RSScript &pScript,
185                                const char* pScriptName,
186                                const char *pOutputPath,
187                                const char *pRuntimePath,
188                                const RSInfo::DependencyTableTy &pDeps,
189                                bool pSkipLoad) {
190  android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
191  RSExecutable *result = NULL;
192  RSInfo *info = NULL;
193
194  //===--------------------------------------------------------------------===//
195  // Extract RS-specific information from source bitcode.
196  //===--------------------------------------------------------------------===//
197  // RS info may contains configuration (such as #optimization_level) to the
198  // compiler therefore it should be extracted before compilation.
199  info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps);
200  if (info == NULL) {
201    return NULL;
202  }
203
204  //===--------------------------------------------------------------------===//
205  // Associate script with its info
206  //===--------------------------------------------------------------------===//
207  // This is required since RS compiler may need information in the info file
208  // to do some transformation (e.g., expand foreach-able function.)
209  pScript.setInfo(info);
210
211  //===--------------------------------------------------------------------===//
212  // Link RS script with Renderscript runtime.
213  //===--------------------------------------------------------------------===//
214  if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
215    ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName);
216    return NULL;
217  }
218
219  //===--------------------------------------------------------------------===//
220  // Acquire the write lock for writing output object file.
221  //===--------------------------------------------------------------------===//
222  FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
223
224  if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
225    ALOGE("Unable to acquire the lock for writing %s! (%s)",
226          pOutputPath, write_output_mutex.getErrorMessage().c_str());
227    return NULL;
228  }
229
230  //===--------------------------------------------------------------------===//
231  // Open the output file for write.
232  //===--------------------------------------------------------------------===//
233  OutputFile *output_file =
234      new (std::nothrow) OutputFile(pOutputPath, FileBase::kTruncate);
235
236  if ((output_file == NULL) || output_file->hasError()) {
237    ALOGE("Unable to open the %s for write! (%s)", pOutputPath,
238          output_file->getErrorMessage().c_str());
239    delete info;
240    delete output_file;
241    return NULL;
242  }
243
244  //===--------------------------------------------------------------------===//
245  // Setup the config to the compiler.
246  //===--------------------------------------------------------------------===//
247  bool compiler_need_reconfigure = setupConfig(pScript);
248
249  if (mConfig == NULL) {
250    ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath);
251    delete info;
252    delete output_file;
253    return NULL;
254  }
255
256  // Compiler need to re-config if it's haven't run the config() yet or the
257  // configuration it referenced is changed.
258  if (compiler_need_reconfigure) {
259    Compiler::ErrorCode err = mCompiler.config(*mConfig);
260    if (err != Compiler::kSuccess) {
261      ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
262            Compiler::GetErrorString(err));
263      delete info;
264      delete output_file;
265      return NULL;
266    }
267  }
268
269  //===--------------------------------------------------------------------===//
270  // Run the compiler.
271  //===--------------------------------------------------------------------===//
272  Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
273  if (compile_result != Compiler::kSuccess) {
274    ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
275          Compiler::GetErrorString(compile_result));
276    delete info;
277    delete output_file;
278    return NULL;
279  }
280
281  // No need to produce an RSExecutable in this case.
282  // TODO: Error handling in this case is nonexistent.
283  if (pSkipLoad) {
284    return NULL;
285  }
286
287  //===--------------------------------------------------------------------===//
288  // Create the RSExecutable.
289  //===--------------------------------------------------------------------===//
290  result = RSExecutable::Create(*info, *output_file, mResolver);
291  if (result == NULL) {
292    delete info;
293    delete output_file;
294    return NULL;
295  }
296
297  //===--------------------------------------------------------------------===//
298  // Dump the disassembly for debug when possible.
299  //===--------------------------------------------------------------------===//
300#if USE_DISASSEMBLER
301  OutputFile *disassembly_output =
302      new (std::nothrow) OutputFile(DEBUG_DISASSEMBLER_FILE,
303                                    FileBase::kAppend);
304
305  if (disassembly_output != NULL) {
306    result->dumpDisassembly(*disassembly_output);
307    delete disassembly_output;
308  }
309#endif
310
311  //===--------------------------------------------------------------------===//
312  // Write out the RS info file.
313  //===--------------------------------------------------------------------===//
314  // Note that write failure only results in a warning since the source is
315  // successfully compiled and loaded.
316  if (!result->syncInfo(/* pForce */true)) {
317    ALOGW("%s was successfully compiled and loaded but its RS info file failed "
318          "to write out!", pOutputPath);
319  }
320
321  return result;
322}
323
324RSExecutable *RSCompilerDriver::build(BCCContext &pContext,
325                                      const char *pCacheDir,
326                                      const char *pResName,
327                                      const char *pBitcode,
328                                      size_t pBitcodeSize,
329                                      const char *pRuntimePath) {
330  android::StopWatch build_time("bcc: RSCompilerDriver::build time");
331  //===--------------------------------------------------------------------===//
332  // Check parameters.
333  //===--------------------------------------------------------------------===//
334  if ((pCacheDir == NULL) || (pResName == NULL)) {
335    ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
336          "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
337                                    ((pResName) ? pResName : "(null)"));
338    return NULL;
339  }
340
341  if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
342    ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
343          pBitcode, static_cast<unsigned>(pBitcodeSize));
344    return NULL;
345  }
346
347  //===--------------------------------------------------------------------===//
348  // Prepare dependency information.
349  //===--------------------------------------------------------------------===//
350  RSInfo::DependencyTableTy dep_info;
351  uint8_t bitcode_sha1[20];
352  Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
353  dep_info.push(std::make_pair(pResName, bitcode_sha1));
354
355  //===--------------------------------------------------------------------===//
356  // Construct output path.
357  //===--------------------------------------------------------------------===//
358  llvm::sys::Path output_path(pCacheDir);
359
360  // {pCacheDir}/{pResName}
361  if (!output_path.appendComponent(pResName)) {
362    ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
363    return NULL;
364  }
365
366  // {pCacheDir}/{pResName}.o
367  output_path.appendSuffix("o");
368
369  //===--------------------------------------------------------------------===//
370  // Load cache.
371  //===--------------------------------------------------------------------===//
372  RSExecutable *result = loadScriptCache(output_path.c_str(), dep_info);
373
374  if (result != NULL) {
375    // Cache hit
376    return result;
377  }
378
379  //===--------------------------------------------------------------------===//
380  // Load the bitcode and create script.
381  //===--------------------------------------------------------------------===//
382  Source *source = Source::CreateFromBuffer(pContext, pResName,
383                                            pBitcode, pBitcodeSize);
384  if (source == NULL) {
385    return NULL;
386  }
387
388  RSScript *script = new (std::nothrow) RSScript(*source);
389  if (script == NULL) {
390    ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
391          pResName, output_path.c_str());
392    delete source;
393    return NULL;
394  }
395
396  // Read information from bitcode wrapper.
397  bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
398  script->setCompilerVersion(wrapper.getCompilerVersion());
399  script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
400                                   wrapper.getOptimizationLevel()));
401
402  //===--------------------------------------------------------------------===//
403  // Compile the script
404  //===--------------------------------------------------------------------===//
405  result = compileScript(*script, pResName, output_path.c_str(), pRuntimePath,
406                         dep_info, false);
407
408  // Script is no longer used. Free it to get more memory.
409  delete script;
410
411  if (result == NULL) {
412    return NULL;
413  }
414
415  return result;
416}
417
418
419RSExecutable *RSCompilerDriver::build(RSScript &pScript, const char *pOut,
420                                      const char *pRuntimePath) {
421  RSInfo::DependencyTableTy dep_info;
422  RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info);
423  if (info == NULL) {
424    return NULL;
425  }
426  pScript.setInfo(info);
427
428  // Embed the info string directly in the ELF, since this path is for an
429  // offline (host) compilation.
430  pScript.setEmbedInfo(true);
431
432  RSExecutable *result = compileScript(pScript, pOut, pOut, pRuntimePath,
433                                       dep_info, true);
434  return result;
435}
436
437