docs: private List<String> loadBalanceSuites(List<ForkedJvmInfo> jvmInfo,
        TestsCollection testsCollection, List<SuiteBalancer> balancers) {
      
      // Order test suites identically for balancers.
      // and split into replicated and non-replicated suites.
      Map<Boolean,List<String>> partitioned = sortAndSplitReplicated(testsCollection.testClasses);
  
      Collection<String> replicated = partitioned.get(true);
      Collection<String> suites     = partitioned.get(false);
  
      final List<SuiteBalancer> balancersWithFallback = new ArrayList<>(balancers);
      balancersWithFallback.add(new RoundRobinBalancer());
  
      // Go through all the balancers, the first one to assign a suite wins.
      final List<String> remaining = new ArrayList<>(suites);
      Collections.sort(remaining);
  
      final Map<Integer,List<Assignment>> perJvmAssignments = new HashMap<>();
      for (ForkedJvmInfo si : jvmInfo) {
        perJvmAssignments.put(si.id, new ArrayList<Assignment>());
      }
      final int jvmCount = jvmInfo.size();
      for (SuiteBalancer balancer : balancersWithFallback) {
        balancer.setOwner(this);
        final List<Assignment> assignments =
            balancer.assign(
                Collections.unmodifiableCollection(remaining), jvmCount, masterSeed());
  
        for (Assignment e : assignments) {
          if (e == null) {
            throw new RuntimeException("Balancer must return non-null assignments.");
          }
          if (!remaining.remove(e.suiteName)) {
            throw new RuntimeException("Balancer must return suite name as a key: " + e.suiteName);
          }
  
          log(String.format(Locale.ROOT,
              "Assignment hint: J%-2d (cost %5d) %s (by %s)",
              e.slaveId,
              e.estimatedCost,
              e.suiteName,
              balancer.getClass().getSimpleName()), Project.MSG_VERBOSE);
  
          perJvmAssignments.get(e.slaveId).add(e);
        }
      }
  
      if (remaining.size() != 0) {
        throw new RuntimeException("Not all suites assigned?: " + remaining);
      }
  
      if (shuffleOnSlave) {
        // Shuffle suites on slaves so that the result is always the same wrt master seed
        // (sort first, then shuffle with a constant seed).
        for (List<Assignment> assignments : perJvmAssignments.values()) {
          Collections.sort(assignments);
          Collections.shuffle(assignments, new Random(this.masterSeed()));
        }
      }
  
      // Take a fraction of suites scheduled as last on each slave and move them to a common
      // job-stealing queue.
      List<SuiteHint> stealingQueueWithHints = new ArrayList<>();
      for (ForkedJvmInfo si : jvmInfo) {
        final List<Assignment> assignments = perJvmAssignments.get(si.id);
        int moveToCommon = (int) (assignments.size() * dynamicAssignmentRatio);
  
        if (moveToCommon > 0) {
          final List<Assignment> movedToCommon = 
              assignments.subList(assignments.size() - moveToCommon, assignments.size());
          for (Assignment a : movedToCommon) {
            stealingQueueWithHints.add(new SuiteHint(a.suiteName, a.estimatedCost));
          }
          movedToCommon.clear();
        }
  
        final ArrayList<String> slaveSuites = (si.testSuites = new ArrayList<>());
        for (Assignment a : assignments) {
          slaveSuites.add(a.suiteName);
        }
      }
  
      // Sort stealing queue according to descending cost.
      Collections.sort(stealingQueueWithHints, SuiteHint.DESCENDING_BY_WEIGHT);
  
      // Append all replicated suites to each forked JVM, AFTER we process the stealing queue
      // to enforce all replicated suites run on each bound JVM.
      if (!replicated.isEmpty()) {
        for (ForkedJvmInfo si : jvmInfo) {
          for (String suite : replicated) {
              si.testSuites.add(suite);
          }
          if (shuffleOnSlave) {
            // Shuffle suites on slaves so that the result is always the same wrt master seed
            // (sort first, then shuffle with a constant seed).
            Collections.shuffle(si.testSuites, new Random(this.masterSeed()));
          }
        }
      }
  
      // Dump scheduling information.
      for (ForkedJvmInfo si : jvmInfo) {
        log("Forked JVM J" + si.id + " assignments (after shuffle):", Project.MSG_VERBOSE);
        for (String suiteName : si.testSuites) {
          log("  " + suiteName, Project.MSG_VERBOSE);
        }
      }
  
      log("Stealing queue:", Project.MSG_VERBOSE);
      for (SuiteHint suiteHint : stealingQueueWithHints) {
        log("  " + suiteHint.suiteName + " " + suiteHint.cost, Project.MSG_VERBOSE);
      }
  
      List<String> stealingQueue = new ArrayList<>(stealingQueueWithHints.size());
      for (SuiteHint suiteHint : stealingQueueWithHints) {
        stealingQueue.add(suiteHint.suiteName);
      }
      return stealingQueue;
    }