Search in sources :

Example 1 with RoundRobinBalancer

use of com.carrotsearch.ant.tasks.junit4.balancers.RoundRobinBalancer in project randomizedtesting by randomizedtesting.

the class JUnit4 method loadBalanceSuites.

/**
   * Perform load balancing of the set of suites. Sets {@link ForkedJvmInfo#testSuites}
   * to suites preassigned to a given slave and returns a pool of suites
   * that should be load-balanced dynamically based on job stealing.
   */
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) {
        // (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);
    // 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;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) SuiteHint(com.carrotsearch.ant.tasks.junit4.balancers.SuiteHint) Assignment(com.carrotsearch.ant.tasks.junit4.SuiteBalancer.Assignment) Random(java.util.Random) SuiteHint(com.carrotsearch.ant.tasks.junit4.balancers.SuiteHint) ArrayList(java.util.ArrayList) List(java.util.List) RoundRobinBalancer(com.carrotsearch.ant.tasks.junit4.balancers.RoundRobinBalancer) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean)

Aggregations

Assignment (com.carrotsearch.ant.tasks.junit4.SuiteBalancer.Assignment)1 RoundRobinBalancer (com.carrotsearch.ant.tasks.junit4.balancers.RoundRobinBalancer)1 SuiteHint (com.carrotsearch.ant.tasks.junit4.balancers.SuiteHint)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Random (java.util.Random)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1