Profman: Use method_percentage and class_percentage values passed for generating profiles

The percentage was only used for profiles without dex files, however, this
could also be used when the dex files are provided.

Test: manual
Change-Id: Ia8eff4231951b6531ce887938ae2eb10ea502089
diff --git a/profman/profman.cc b/profman/profman.cc
index fd3bd11..d0c99e0 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -116,9 +116,9 @@
   UsageError("  --generate-test-profile=<filename>: generates a random profile file for testing.");
   UsageError("  --generate-test-profile-num-dex=<number>: number of dex files that should be");
   UsageError("      included in the generated profile. Defaults to 20.");
-  UsageError("  --generate-test-profile-method-ratio=<number>: the percentage from the maximum");
+  UsageError("  --generate-test-profile-method-percentage=<number>: the percentage from the maximum");
   UsageError("      number of methods that should be generated. Defaults to 5.");
-  UsageError("  --generate-test-profile-class-ratio=<number>: the percentage from the maximum");
+  UsageError("  --generate-test-profile-class-percentage=<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.");
@@ -151,8 +151,8 @@
 
 // Note: make sure you update the Usage if you change these values.
 static constexpr uint16_t kDefaultTestProfileNumDex = 20;
-static constexpr uint16_t kDefaultTestProfileMethodRatio = 5;
-static constexpr uint16_t kDefaultTestProfileClassRatio = 5;
+static constexpr uint16_t kDefaultTestProfileMethodPercentage = 5;
+static constexpr uint16_t kDefaultTestProfileClassPercentage = 5;
 
 // Separators used when parsing human friendly representation of profiles.
 static const std::string kMethodSep = "->";
@@ -178,8 +178,8 @@
       generate_boot_image_profile_(false),
       dump_output_to_fd_(kInvalidFd),
       test_profile_num_dex_(kDefaultTestProfileNumDex),
-      test_profile_method_ratio_(kDefaultTestProfileMethodRatio),
-      test_profile_class_ratio_(kDefaultTestProfileClassRatio),
+      test_profile_method_percerntage_(kDefaultTestProfileMethodPercentage),
+      test_profile_class_percentage_(kDefaultTestProfileClassPercentage),
       test_profile_seed_(NanoTime()),
       start_ns_(NanoTime()) {}
 
@@ -253,15 +253,15 @@
                         "--generate-test-profile-num-dex",
                         &test_profile_num_dex_,
                         Usage);
-      } else if (option.starts_with("--generate-test-profile-method-ratio")) {
+      } else if (option.starts_with("--generate-test-profile-method-percentage")) {
         ParseUintOption(option,
-                        "--generate-test-profile-method-ratio",
-                        &test_profile_method_ratio_,
+                        "--generate-test-profile-method-percentage",
+                        &test_profile_method_percerntage_,
                         Usage);
-      } else if (option.starts_with("--generate-test-profile-class-ratio")) {
+      } else if (option.starts_with("--generate-test-profile-class-percentage")) {
         ParseUintOption(option,
-                        "--generate-test-profile-class-ratio",
-                        &test_profile_class_ratio_,
+                        "--generate-test-profile-class-percentage",
+                        &test_profile_class_percentage_,
                         Usage);
       } else if (option.starts_with("--generate-test-profile-seed=")) {
         ParseUintOption(option, "--generate-test-profile-seed", &test_profile_seed_, Usage);
@@ -1014,11 +1014,11 @@
 
   int GenerateTestProfile() {
     // Validate parameters for this command.
-    if (test_profile_method_ratio_ > 100) {
-      Usage("Invalid ratio for --generate-test-profile-method-ratio");
+    if (test_profile_method_percerntage_ > 100) {
+      Usage("Invalid percentage for --generate-test-profile-method-percentage");
     }
-    if (test_profile_class_ratio_ > 100) {
-      Usage("Invalid ratio for --generate-test-profile-class-ratio");
+    if (test_profile_class_percentage_ > 100) {
+      Usage("Invalid percentage for --generate-test-profile-class-percentage");
     }
     // If given APK files or DEX locations, check that they're ok.
     if (!apk_files_.empty() || !apks_fd_.empty() || !dex_locations_.empty()) {
@@ -1039,8 +1039,8 @@
     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_method_percerntage_,
+                                                           test_profile_class_percentage_,
                                                            test_profile_seed_);
     } else {
       // Initialize MemMap for ZipArchive::OpenFromFd.
@@ -1051,6 +1051,8 @@
       // Create a random profile file based on the set of dex files.
       result = ProfileCompilationInfo::GenerateTestProfile(profile_test_fd,
                                                            dex_files,
+                                                           test_profile_method_percerntage_,
+                                                           test_profile_class_percentage_,
                                                            test_profile_seed_);
     }
     close(profile_test_fd);  // ignore close result.
@@ -1101,8 +1103,8 @@
   std::string test_profile_;
   std::string create_profile_from_file_;
   uint16_t test_profile_num_dex_;
-  uint16_t test_profile_method_ratio_;
-  uint16_t test_profile_class_ratio_;
+  uint16_t test_profile_method_percerntage_;
+  uint16_t test_profile_class_percentage_;
   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 c9bfc9c..0cbcebc 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -343,10 +343,6 @@
                << " bytes. Profile will not be written to disk.";
     return false;
   }
-  if (required_capacity > kProfileSizeWarningThresholdInBytes) {
-    LOG(WARNING) << "Profile data size exceeds "
-                 << std::to_string(kProfileSizeWarningThresholdInBytes);
-  }
   AddUintToBuffer(&buffer, required_capacity);
   if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
     return false;
@@ -413,6 +409,11 @@
                                                                required_capacity,
                                                                &output_size);
 
+  if (output_size > kProfileSizeWarningThresholdInBytes) {
+    LOG(WARNING) << "Profile data size exceeds "
+                 << std::to_string(kProfileSizeWarningThresholdInBytes);
+  }
+
   buffer.clear();
   AddUintToBuffer(&buffer, output_size);
 
@@ -1488,16 +1489,16 @@
 // Naive implementation to generate a random profile file suitable for testing.
 bool ProfileCompilationInfo::GenerateTestProfile(int fd,
                                                  uint16_t number_of_dex_files,
-                                                 uint16_t method_ratio,
-                                                 uint16_t class_ratio,
+                                                 uint16_t method_percentage,
+                                                 uint16_t class_percentage,
                                                  uint32_t random_seed) {
   const std::string base_dex_location = "base.apk";
   ProfileCompilationInfo info;
   // The limits are defined by the dex specification.
   const uint16_t max_method = std::numeric_limits<uint16_t>::max();
   const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
-  uint16_t number_of_methods = max_method * method_ratio / 100;
-  uint16_t number_of_classes = max_classes * class_ratio / 100;
+  uint16_t number_of_methods = max_method * method_percentage / 100;
+  uint16_t number_of_classes = max_classes * class_percentage / 100;
 
   std::srand(random_seed);
 
@@ -1534,28 +1535,47 @@
 }
 
 // Naive implementation to generate a random profile file suitable for testing.
+// Description of random selection:
+// * Select a random starting point S.
+// * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
+//   probably of 1/(N - i - number of methods/classes needed to add in profile).
 bool ProfileCompilationInfo::GenerateTestProfile(
     int fd,
     std::vector<std::unique_ptr<const DexFile>>& dex_files,
+    uint16_t method_percentage,
+    uint16_t class_percentage,
     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) {
+
+    uint32_t number_of_classes = dex_file->NumClassDefs();
+    uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
+    uint32_t class_start_index = rand() % number_of_classes;
+    for (uint32_t i = 0; i < number_of_classes && classes_required_in_profile; ++i) {
+      if (number_of_classes - i == classes_required_in_profile ||
+          std::rand() % (number_of_classes - i - classes_required_in_profile) == 0) {
+        uint32_t class_index = (i + class_start_index) % number_of_classes;
         info.AddClassIndex(location,
                            checksum,
-                           dex_file->GetClassDef(i).class_idx_,
+                           dex_file->GetClassDef(class_index).class_idx_,
                            dex_file->NumMethodIds());
+        classes_required_in_profile--;
       }
     }
-    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(MethodHotness::kFlagHot, MethodReference(dex_file.get(), i));
+
+    uint32_t number_of_methods = dex_file->NumMethodIds();
+    uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
+    uint32_t method_start_index = rand() % number_of_methods;
+    for (uint32_t i = 0; i < number_of_methods && methods_required_in_profile; ++i) {
+      if (number_of_methods - i == methods_required_in_profile ||
+          std::rand() % (number_of_methods - i - methods_required_in_profile) == 0) {
+        uint32_t method_index = (method_start_index + i) % number_of_methods;
+        info.AddMethodIndex(MethodHotness::kFlagHot, MethodReference(dex_file.get(),
+                                                                     method_index));
+        methods_required_in_profile--;
       }
     }
   }
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index ffb67ae..6d1fb27 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -372,6 +372,8 @@
   // the provided list of dex files.
   static bool GenerateTestProfile(int fd,
                                   std::vector<std::unique_ptr<const DexFile>>& dex_files,
+                                  uint16_t method_percentage,
+                                  uint16_t class_percentage,
                                   uint32_t random_seed);
 
   // Check that the given profile method info contain the same data.