diff options
| author | 2017-03-28 19:39:16 +0000 | |
|---|---|---|
| committer | 2017-03-28 19:39:16 +0000 | |
| commit | f8d00ff206e33ff66fcabcf75d6b5bbe30cddb98 (patch) | |
| tree | 80b8c5fc8312963d20001628209d63090d687533 | |
| parent | ddacd7e580e64fa87d55cac0d5766e8d6b66fbcd (diff) | |
| parent | f0a31f865c3b3e5843ddd52f015c70293b54b4e4 (diff) | |
Merge "Add profman option to generate a random profile based on dex files."
| -rw-r--r-- | profman/profile_assistant_test.cc | 23 | ||||
| -rw-r--r-- | profman/profman.cc | 38 | ||||
| -rw-r--r-- | runtime/jit/profile_compilation_info.cc | 31 | ||||
| -rw-r--r-- | runtime/jit/profile_compilation_info.h | 9 |
4 files changed, 93 insertions, 8 deletions
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index 1a8a614a4a..e2f622db42 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -99,6 +99,18 @@ class ProfileAssistantTest : public CommonRuntimeTest { return ExecAndReturnCode(argv_str, &error); } + bool GenerateTestProfileWithInputDex(const std::string& filename) { + std::string profman_cmd = GetProfmanCmd(); + std::vector<std::string> argv_str; + argv_str.push_back(profman_cmd); + argv_str.push_back("--generate-test-profile=" + filename); + argv_str.push_back("--generate-test-profile-seed=0"); + argv_str.push_back("--apk=" + GetLibCoreDexFileNames()[0]); + argv_str.push_back("--dex-location=" + GetLibCoreDexFileNames()[0]); + std::string error; + return ExecAndReturnCode(argv_str, &error); + } + bool CreateProfile(std::string profile_file_contents, const std::string& filename, const std::string& dex_location) { @@ -425,6 +437,17 @@ TEST_F(ProfileAssistantTest, TestProfileGeneration) { ASSERT_TRUE(info.Load(GetFd(profile))); } +TEST_F(ProfileAssistantTest, TestProfileGenerationWithIndexDex) { + ScratchFile profile; + // Generate a test profile passing in a dex file as reference. + GenerateTestProfileWithInputDex(profile.GetFilename()); + + // Verify that the generated profile is valid and can be loaded. + ASSERT_TRUE(profile.GetFile()->ResetOffset()); + ProfileCompilationInfo info; + ASSERT_TRUE(info.Load(GetFd(profile))); +} + TEST_F(ProfileAssistantTest, TestProfileCreationAllMatch) { // Class names put here need to be in sorted order. std::vector<std::string> class_names = { diff --git a/profman/profman.cc b/profman/profman.cc index dac95b8e18..5504695a96 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -117,6 +117,8 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" number of methods that should be generated. Defaults to 5."); UsageError(" --generate-test-profile-class-ratio=<number>: the percentage from the maximum"); UsageError(" number of classes that should be generated. Defaults to 5."); + UsageError(" --generate-test-profile-seed=<number>: seed for random number generator used when"); + UsageError(" generating random test profiles. Defaults to using NanoTime."); UsageError(""); UsageError(" --create-profile-from=<filename>: creates a profile from a list of classes."); UsageError(""); @@ -156,6 +158,7 @@ class ProfMan FINAL { test_profile_num_dex_(kDefaultTestProfileNumDex), test_profile_method_ratio_(kDefaultTestProfileMethodRatio), test_profile_class_ratio_(kDefaultTestProfileClassRatio), + test_profile_seed_(NanoTime()), start_ns_(NanoTime()) {} ~ProfMan() { @@ -221,6 +224,8 @@ class ProfMan FINAL { "--generate-test-profile-class-ratio", &test_profile_class_ratio_, Usage); + } else if (option.starts_with("--generate-test-profile-seed=")) { + ParseUintOption(option, "--generate-test-profile-seed", &test_profile_seed_, Usage); } else { Usage("Unknown argument '%s'", option.data()); } @@ -798,17 +803,39 @@ class ProfMan FINAL { if (test_profile_class_ratio_ > 100) { Usage("Invalid ratio for --generate-test-profile-class-ratio"); } + // If given APK files or DEX locations, check that they're ok. + if (!apk_files_.empty() || !apks_fd_.empty() || !dex_locations_.empty()) { + if (apk_files_.empty() && apks_fd_.empty()) { + Usage("APK files must be specified when passing DEX locations to --generate-test-profile"); + } + if (dex_locations_.empty()) { + Usage("DEX locations must be specified when passing APK files to --generate-test-profile"); + } + } // ShouldGenerateTestProfile confirms !test_profile_.empty(). int profile_test_fd = open(test_profile_.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644); if (profile_test_fd < 0) { LOG(ERROR) << "Cannot open " << test_profile_ << strerror(errno); return -1; } - - bool result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd, - test_profile_num_dex_, - test_profile_method_ratio_, - test_profile_class_ratio_); + bool result; + if (apk_files_.empty() && apks_fd_.empty() && dex_locations_.empty()) { + result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd, + test_profile_num_dex_, + test_profile_method_ratio_, + test_profile_class_ratio_, + test_profile_seed_); + } else { + // Initialize MemMap for ZipArchive::OpenFromFd. + MemMap::Init(); + // Open the dex files to look up classes and methods. + std::vector<std::unique_ptr<const DexFile>> dex_files; + OpenApkFilesFromLocations(&dex_files); + // Create a random profile file based on the set of dex files. + result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd, + dex_files, + test_profile_seed_); + } close(profile_test_fd); // ignore close result. return result ? 0 : -1; } @@ -857,6 +884,7 @@ class ProfMan FINAL { uint16_t test_profile_num_dex_; uint16_t test_profile_method_ratio_; uint16_t test_profile_class_ratio_; + uint32_t test_profile_seed_; uint64_t start_ns_; }; diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc index a2c459c530..f951065c8a 100644 --- a/runtime/jit/profile_compilation_info.cc +++ b/runtime/jit/profile_compilation_info.cc @@ -1130,7 +1130,8 @@ void ProfileCompilationInfo::ClearResolvedClasses() { bool ProfileCompilationInfo::GenerateTestProfile(int fd, uint16_t number_of_dex_files, uint16_t method_ratio, - uint16_t class_ratio) { + uint16_t class_ratio, + uint32_t random_seed) { const std::string base_dex_location = "base.apk"; ProfileCompilationInfo info; // The limits are defined by the dex specification. @@ -1139,7 +1140,7 @@ bool ProfileCompilationInfo::GenerateTestProfile(int fd, uint16_t number_of_methods = max_method * method_ratio / 100; uint16_t number_of_classes = max_classes * class_ratio / 100; - srand(MicroTime()); + std::srand(random_seed); // Make sure we generate more samples with a low index value. // This makes it more likely to hit valid method/class indices in small apps. @@ -1169,6 +1170,32 @@ bool ProfileCompilationInfo::GenerateTestProfile(int fd, return info.Save(fd); } +// Naive implementation to generate a random profile file suitable for testing. +bool ProfileCompilationInfo::GenerateTestProfile( + int fd, + std::vector<std::unique_ptr<const DexFile>>& dex_files, + uint32_t random_seed) { + std::srand(random_seed); + ProfileCompilationInfo info; + for (std::unique_ptr<const DexFile>& dex_file : dex_files) { + const std::string& location = dex_file->GetLocation(); + uint32_t checksum = dex_file->GetLocationChecksum(); + for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { + // Randomly add a class from the dex file (with 50% chance). + if (std::rand() % 2 != 0) { + info.AddClassIndex(location, checksum, dex::TypeIndex(dex_file->GetClassDef(i).class_idx_)); + } + } + for (uint32_t i = 0; i < dex_file->NumMethodIds(); ++i) { + // Randomly add a method from the dex file (with 50% chance). + if (std::rand() % 2 != 0) { + info.AddMethodIndex(location, checksum, i); + } + } + } + return info.Save(fd); +} + bool ProfileCompilationInfo::OfflineProfileMethodInfo::operator==( const OfflineProfileMethodInfo& other) const { if (inline_caches.size() != other.inline_caches.size()) { diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h index 451d53e5d7..c3ac78f580 100644 --- a/runtime/jit/profile_compilation_info.h +++ b/runtime/jit/profile_compilation_info.h @@ -253,7 +253,14 @@ class ProfileCompilationInfo { static bool GenerateTestProfile(int fd, uint16_t number_of_dex_files, uint16_t method_ratio, - uint16_t class_ratio); + uint16_t class_ratio, + uint32_t random_seed); + + // Generate a test profile which will randomly contain classes and methods from + // the provided list of dex files. + static bool GenerateTestProfile(int fd, + std::vector<std::unique_ptr<const DexFile>>& dex_files, + uint32_t random_seed); // Check that the given profile method info contain the same data. static bool Equals(const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi1, |