Home | History | Annotate | Download | only in Renderscript
      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 
     39 using namespace bcc;
     40 
     41 namespace {
     42 
     43 bool 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 
     63 RSCompilerDriver::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 
     74 RSCompilerDriver::~RSCompilerDriver() {
     75   delete mCompilerRuntime;
     76   delete mConfig;
     77 }
     78 
     79 RSExecutable *
     80 RSCompilerDriver::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 
    151 bool 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 
    188 RSExecutable *
    189 RSCompilerDriver::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   //===--------------------------------------------------------------------===//
    225   // Acquire the write lock for writing output object file.
    226   //===--------------------------------------------------------------------===//
    227   FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
    228 
    229   if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
    230     ALOGE("Unable to acquire the lock for writing %s! (%s)",
    231           pOutputPath, write_output_mutex.getErrorMessage().c_str());
    232     return NULL;
    233   }
    234 
    235   //===--------------------------------------------------------------------===//
    236   // Open the output file for write.
    237   //===--------------------------------------------------------------------===//
    238   unsigned flags = FileBase::kTruncate;
    239   if (mDebugContext) {
    240     // Delete the cache file when we finish up under a debug context.
    241     flags |= FileBase::kDeleteOnClose;
    242   }
    243   OutputFile *output_file = new (std::nothrow) OutputFile(pOutputPath, flags);
    244 
    245   if ((output_file == NULL) || output_file->hasError()) {
    246       ALOGE("Unable to open %s for write! (%s)", pOutputPath,
    247             output_file->getErrorMessage().c_str());
    248     delete info;
    249     delete output_file;
    250     return NULL;
    251   }
    252 
    253   //===--------------------------------------------------------------------===//
    254   // Setup the config to the compiler.
    255   //===--------------------------------------------------------------------===//
    256   bool compiler_need_reconfigure = setupConfig(pScript);
    257 
    258   if (mConfig == NULL) {
    259     ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath);
    260     delete info;
    261     delete output_file;
    262     return NULL;
    263   }
    264 
    265   // Compiler need to re-config if it's haven't run the config() yet or the
    266   // configuration it referenced is changed.
    267   if (compiler_need_reconfigure) {
    268     Compiler::ErrorCode err = mCompiler.config(*mConfig);
    269     if (err != Compiler::kSuccess) {
    270       ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
    271             Compiler::GetErrorString(err));
    272       delete info;
    273       delete output_file;
    274       return NULL;
    275     }
    276   }
    277 
    278   //===--------------------------------------------------------------------===//
    279   // Run the compiler.
    280   //===--------------------------------------------------------------------===//
    281   Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
    282   if (compile_result != Compiler::kSuccess) {
    283     ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
    284           Compiler::GetErrorString(compile_result));
    285     delete info;
    286     delete output_file;
    287     return NULL;
    288   }
    289 
    290   // No need to produce an RSExecutable in this case.
    291   // TODO: Error handling in this case is nonexistent.
    292   if (pSkipLoad) {
    293     return NULL;
    294   }
    295 
    296   //===--------------------------------------------------------------------===//
    297   // Create the RSExecutable.
    298   //===--------------------------------------------------------------------===//
    299   result = RSExecutable::Create(*info, *output_file, mResolver);
    300   if (result == NULL) {
    301     delete info;
    302     delete output_file;
    303     return NULL;
    304   }
    305 
    306   //===--------------------------------------------------------------------===//
    307   // Dump the disassembly for debug when possible.
    308   //===--------------------------------------------------------------------===//
    309 #if USE_DISASSEMBLER
    310   OutputFile *disassembly_output =
    311       new (std::nothrow) OutputFile(DEBUG_DISASSEMBLER_FILE,
    312                                     FileBase::kAppend);
    313 
    314   if (disassembly_output != NULL) {
    315     result->dumpDisassembly(*disassembly_output);
    316     delete disassembly_output;
    317   }
    318 #endif
    319 
    320   //===--------------------------------------------------------------------===//
    321   // Write out the RS info file.
    322   //===--------------------------------------------------------------------===//
    323   // Note that write failure only results in a warning since the source is
    324   // successfully compiled and loaded.
    325   if (!result->syncInfo(/* pForce */true)) {
    326     ALOGW("%s was successfully compiled and loaded but its RS info file failed "
    327           "to write out!", pOutputPath);
    328   }
    329 
    330   return result;
    331 }
    332 
    333 RSExecutable *RSCompilerDriver::build(BCCContext &pContext,
    334                                       const char *pCacheDir,
    335                                       const char *pResName,
    336                                       const char *pBitcode,
    337                                       size_t pBitcodeSize,
    338                                       const char *pRuntimePath,
    339                                       RSLinkRuntimeCallback pLinkRuntimeCallback) {
    340     //  android::StopWatch build_time("bcc: RSCompilerDriver::build time");
    341   //===--------------------------------------------------------------------===//
    342   // Check parameters.
    343   //===--------------------------------------------------------------------===//
    344   if ((pCacheDir == NULL) || (pResName == NULL)) {
    345     ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
    346           "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
    347                                     ((pResName) ? pResName : "(null)"));
    348     return NULL;
    349   }
    350 
    351   if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
    352     ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
    353           pBitcode, static_cast<unsigned>(pBitcodeSize));
    354     return NULL;
    355   }
    356 
    357   //===--------------------------------------------------------------------===//
    358   // Prepare dependency information.
    359   //===--------------------------------------------------------------------===//
    360   RSInfo::DependencyTableTy dep_info;
    361   uint8_t bitcode_sha1[20];
    362   Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
    363   dep_info.push(std::make_pair(pResName, bitcode_sha1));
    364 
    365   //===--------------------------------------------------------------------===//
    366   // Construct output path.
    367   //===--------------------------------------------------------------------===//
    368   llvm::sys::Path output_path(pCacheDir);
    369 
    370   // {pCacheDir}/{pResName}
    371   if (!output_path.appendComponent(pResName)) {
    372     ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
    373     return NULL;
    374   }
    375 
    376   // {pCacheDir}/{pResName}.o
    377   output_path.appendSuffix("o");
    378 
    379   //===--------------------------------------------------------------------===//
    380   // Load cache.
    381   //===--------------------------------------------------------------------===//
    382   RSExecutable *result = NULL;
    383 
    384   // Skip loading from the cache if we are using a debug context.
    385   if (!mDebugContext) {
    386     result = loadScriptCache(output_path.c_str(), dep_info);
    387 
    388     if (result != NULL) {
    389       // Cache hit
    390       return result;
    391     }
    392   }
    393 
    394   //===--------------------------------------------------------------------===//
    395   // Load the bitcode and create script.
    396   //===--------------------------------------------------------------------===//
    397   Source *source = Source::CreateFromBuffer(pContext, pResName,
    398                                             pBitcode, pBitcodeSize);
    399   if (source == NULL) {
    400     return NULL;
    401   }
    402 
    403   RSScript *script = new (std::nothrow) RSScript(*source);
    404   if (script == NULL) {
    405     ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
    406           pResName, output_path.c_str());
    407     delete source;
    408     return NULL;
    409   }
    410 
    411   script->setLinkRuntimeCallback(pLinkRuntimeCallback);
    412 
    413   // Read information from bitcode wrapper.
    414   bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
    415   script->setCompilerVersion(wrapper.getCompilerVersion());
    416   script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
    417                                    wrapper.getOptimizationLevel()));
    418 
    419   //===--------------------------------------------------------------------===//
    420   // Compile the script
    421   //===--------------------------------------------------------------------===//
    422   result = compileScript(*script, pResName, output_path.c_str(), pRuntimePath,
    423                          dep_info, false);
    424 
    425   // Script is no longer used. Free it to get more memory.
    426   delete script;
    427 
    428   if (result == NULL) {
    429     return NULL;
    430   }
    431 
    432   return result;
    433 }
    434 
    435 
    436 RSExecutable *RSCompilerDriver::build(RSScript &pScript, const char *pOut,
    437                                       const char *pRuntimePath) {
    438   RSInfo::DependencyTableTy dep_info;
    439   RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info);
    440   if (info == NULL) {
    441     return NULL;
    442   }
    443   pScript.setInfo(info);
    444 
    445   // Embed the info string directly in the ELF, since this path is for an
    446   // offline (host) compilation.
    447   pScript.setEmbedInfo(true);
    448 
    449   RSExecutable *result = compileScript(pScript, pOut, pOut, pRuntimePath,
    450                                        dep_info, true);
    451   return result;
    452 }
    453 
    454