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