ART: Refactor test profile generation

Ensure that the right number of classes and methods is selected.

Test: mmma art
Test: m test-art-host
Change-Id: I79c364b46d6161b146d114fdfa1fc7ef7f7a9cd0
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index 9b70e62..f5e08da 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -23,12 +23,15 @@
 #include <unistd.h>
 #include <zlib.h>
 
+#include <algorithm>
 #include <cerrno>
 #include <climits>
 #include <cstdlib>
+#include <iostream>
+#include <numeric>
+#include <random>
 #include <string>
 #include <vector>
-#include <iostream>
 
 #include "android-base/file.h"
 
@@ -1872,43 +1875,42 @@
     uint16_t method_percentage,
     uint16_t class_percentage,
     uint32_t random_seed) {
-  std::srand(random_seed);
   ProfileCompilationInfo info;
+  std::default_random_engine rng(random_seed);
+  auto create_shuffled_range = [&rng](uint32_t take, uint32_t out_of) {
+    CHECK_LE(take, out_of);
+    std::vector<uint32_t> vec(out_of);
+    std::iota(vec.begin(), vec.end(), 0u);
+    std::shuffle(vec.begin(), vec.end(), rng);
+    vec.erase(vec.begin() + take, vec.end());
+    std::sort(vec.begin(), vec.end());
+    return vec;
+  };
   for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
     const std::string& location = dex_file->GetLocation();
     uint32_t checksum = dex_file->GetLocationChecksum();
 
     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(class_index).class_idx_,
-                           dex_file->NumMethodIds());
-        classes_required_in_profile--;
-      }
+    for (uint32_t class_index : create_shuffled_range(classes_required_in_profile,
+                                                      number_of_classes)) {
+      info.AddClassIndex(location,
+                         checksum,
+                         dex_file->GetClassDef(class_index).class_idx_,
+                         dex_file->NumMethodIds());
     }
 
     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;
-        // Alternate between startup and post startup.
-        uint32_t flags = MethodHotness::kFlagHot;
-        flags |= ((method_index & 1) != 0)
-            ? MethodHotness::kFlagPostStartup
-            : MethodHotness::kFlagStartup;
-        info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
-                            MethodReference(dex_file.get(), method_index));
-        methods_required_in_profile--;
-      }
+    for (uint32_t method_index : create_shuffled_range(methods_required_in_profile,
+                                                       number_of_methods)) {
+      // Alternate between startup and post startup.
+      uint32_t flags = MethodHotness::kFlagHot;
+      flags |= ((method_index & 1) != 0)
+                   ? MethodHotness::kFlagPostStartup
+                   : MethodHotness::kFlagStartup;
+      info.AddMethodIndex(static_cast<MethodHotness::Flag>(flags),
+                          MethodReference(dex_file.get(), method_index));
     }
   }
   return info.Save(fd);