summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/dexopt_test.cc13
-rw-r--r--runtime/dexopt_test.h6
-rw-r--r--runtime/native/dalvik_system_DexFile.cc53
-rw-r--r--runtime/oat_file_assistant.cc23
-rw-r--r--runtime/oat_file_assistant.h14
-rw-r--r--runtime/oat_file_assistant_test.cc32
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.