diff options
| -rw-r--r-- | runtime/dexopt_test.cc | 13 | ||||
| -rw-r--r-- | runtime/dexopt_test.h | 6 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 53 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 23 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.h | 14 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 32 |
6 files changed, 133 insertions, 8 deletions
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc index 037d1fb49c..8ce7921287 100644 --- a/runtime/dexopt_test.cc +++ b/runtime/dexopt_test.cc @@ -49,7 +49,8 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, CompilerFilter::Filter filter, bool relocate, bool pic, - bool with_alternate_image) { + bool with_alternate_image, + const char* compilation_reason) { std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA)); std::string dalvik_cache_tmp = dalvik_cache + ".redirected"; std::string oat_location = oat_location_in; @@ -89,6 +90,10 @@ void DexoptTest::GenerateOatForTest(const std::string& dex_location, args.push_back("--boot-image=" + GetImageLocation2()); } + if (compilation_reason != nullptr) { + args.push_back("--compilation-reason=" + std::string(compilation_reason)); + } + std::string error_msg; ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; @@ -155,13 +160,15 @@ void DexoptTest::GenerateOdexForTest(const std::string& dex_location, void DexoptTest::GeneratePicOdexForTest(const std::string& dex_location, const std::string& odex_location, - CompilerFilter::Filter filter) { + CompilerFilter::Filter filter, + const char* compilation_reason) { GenerateOatForTest(dex_location, odex_location, filter, /*relocate*/false, /*pic*/true, - /*with_alternate_image*/false); + /*with_alternate_image*/false, + compilation_reason); } void DexoptTest::GenerateOatForTest(const char* dex_location, diff --git a/runtime/dexopt_test.h b/runtime/dexopt_test.h index 5f0eafd8eb..6e8dc097d5 100644 --- a/runtime/dexopt_test.h +++ b/runtime/dexopt_test.h @@ -46,7 +46,8 @@ class DexoptTest : public Dex2oatEnvironmentTest { CompilerFilter::Filter filter, bool relocate, bool pic, - bool with_alternate_image); + bool with_alternate_image, + const char* compilation_reason = nullptr); // Generate a non-PIC odex file for the purposes of test. // The generated odex file will be un-relocated. @@ -56,7 +57,8 @@ class DexoptTest : public Dex2oatEnvironmentTest { void GeneratePicOdexForTest(const std::string& dex_location, const std::string& odex_location, - CompilerFilter::Filter filter); + CompilerFilter::Filter filter, + const char* compilation_reason = nullptr); // Generate an oat file for the given dex location in its oat location (under // the dalvik cache). diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 6ea9a7ad62..b49209c4cf 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -549,6 +549,55 @@ static jstring DexFile_getDexFileStatus(JNIEnv* env, return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str()); } +// Return an array specifying the optimization status of the given file. +// The array specification is [compiler_filter, compiler_reason]. +static jobjectArray DexFile_getDexFileOptimizationStatus(JNIEnv* env, + jclass, + jstring javaFilename, + jstring javaInstructionSet) { + ScopedUtfChars filename(env, javaFilename); + if (env->ExceptionCheck()) { + return nullptr; + } + + ScopedUtfChars instruction_set(env, javaInstructionSet); + if (env->ExceptionCheck()) { + return nullptr; + } + + const InstructionSet target_instruction_set = GetInstructionSetFromString( + instruction_set.c_str()); + if (target_instruction_set == InstructionSet::kNone) { + ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); + std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); + env->ThrowNew(iae.get(), message.c_str()); + return nullptr; + } + + std::string compilation_filter; + std::string compilation_reason; + OatFileAssistant::GetOptimizationStatus( + filename.c_str(), target_instruction_set, &compilation_filter, &compilation_reason); + + ScopedLocalRef<jstring> j_compilation_filter(env, env->NewStringUTF(compilation_filter.c_str())); + if (j_compilation_filter.get() == nullptr) { + return nullptr; + } + ScopedLocalRef<jstring> j_compilation_reason(env, env->NewStringUTF(compilation_reason.c_str())); + if (j_compilation_reason.get() == nullptr) { + return nullptr; + } + + // Now create output array and copy the set into it. + jobjectArray result = env->NewObjectArray(2, + WellKnownClasses::java_lang_String, + nullptr); + env->SetObjectArrayElement(result, 0, j_compilation_filter.get()); + env->SetObjectArrayElement(result, 1, j_compilation_reason.get()); + + return result; +} + static jint DexFile_getDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename, @@ -801,7 +850,9 @@ static JNINativeMethod gMethods[] = { "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(DexFile, getDexFileOutputPaths, "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), - NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J") + NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"), + NATIVE_METHOD(DexFile, getDexFileOptimizationStatus, + "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;") }; void register_dalvik_system_DexFile(JNIEnv* env) { diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 15a5954396..0170073e29 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -1262,4 +1262,27 @@ std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() { } return std::unique_ptr<OatFile>(); } + +// TODO(calin): we could provide a more refined status here +// (e.g. run from uncompressed apk, run with vdex but not oat etc). It will allow us to +// track more experiments but adds extra complexity. +void OatFileAssistant::GetOptimizationStatus( + const std::string& filename, + InstructionSet isa, + std::string* out_compilation_filter, + std::string* out_compilation_reason) { + // Try to load the oat file as we would do at runtime. + OatFileAssistant oat_file_assistant(filename.c_str(), isa, true /* load_executable */); + std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); + + if (oat_file == nullptr) { + *out_compilation_filter = "run-from-apk"; + *out_compilation_reason = "unknown"; + } else { + *out_compilation_filter = CompilerFilter::NameOfFilter(oat_file->GetCompilerFilter()); + const char* reason = oat_file->GetCompilationReason(); + *out_compilation_reason = reason == nullptr ? "unknown" : reason; + } +} + } // namespace art diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index a6140304c2..a184807b73 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -226,6 +226,20 @@ class OatFileAssistant { // dex file. The returned description is for debugging purposes only. std::string GetStatusDump(); + // Computes the optimization status of the given dex file. The result is + // returned via the two output parameters. + // - out_compilation_filter: the level of optimizations (compiler filter) + // - out_compilation_reason: the optimization reason. The reason might + // be "unknown" if the compiler artifacts were not annotated during optimizations. + // + // This method will try to mimic the runtime effect of loading the dex file. + // For example, if there is no usable oat file, the compiler filter will be set + // to "run-from-apk". + static void GetOptimizationStatus(const std::string& filename, + InstructionSet isa, + std::string* out_compilation_filter, + std::string* out_compilation_reason); + // Open and returns an image space associated with the oat file. static std::unique_ptr<gc::space::ImageSpace> OpenImageSpace(const OatFile* oat_file); diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 50f5e7a0d5..72f7d02892 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -43,7 +43,27 @@ namespace art { static const std::string kSpecialSharedLibrary = "&"; // NOLINT [runtime/string] [4] static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr; -class OatFileAssistantTest : public DexoptTest {}; +class OatFileAssistantTest : public DexoptTest { + public: + void VerifyOptimizationStatus(const std::string& file, + const std::string& expected_filter, + const std::string& expected_reason) { + std::string compilation_filter; + std::string compilation_reason; + OatFileAssistant::GetOptimizationStatus( + file, kRuntimeISA, &compilation_filter, &compilation_reason); + + ASSERT_EQ(expected_filter, compilation_filter); + ASSERT_EQ(expected_reason, compilation_reason); + } + + void VerifyOptimizationStatus(const std::string& file, + CompilerFilter::Filter expected_filter, + const std::string& expected_reason) { + VerifyOptimizationStatus( + file, CompilerFilter::NameOfFilter(expected_filter), expected_reason); + } +}; class OatFileAssistantNoDex2OatTest : public DexoptTest { public: @@ -107,6 +127,8 @@ TEST_F(OatFileAssistantTest, DexNoOat) { EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); + + VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown"); } // Case: We have no DEX file and no OAT file. @@ -136,7 +158,7 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) { std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar"; std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex"; Copy(GetDexSrc1(), dex_location); - GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); + GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install"); // For the use of oat location by making the dex parent not writable. OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); @@ -154,6 +176,8 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) { EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); + + VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install"); } // Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex @@ -221,6 +245,8 @@ TEST_F(OatFileAssistantTest, OatUpToDate) { EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); + + VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown"); } // Case: Passing valid file descriptors of updated odex/vdex filesalong with @@ -381,6 +407,8 @@ TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) { // Make sure we don't crash in this case when we dump the status. We don't // care what the actual dumped value is. oat_file_assistant.GetStatusDump(); + + VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown"); } // Case: We have a DEX file and empty VDEX and ODEX files. |