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