@ Override public List < Assignment > assign ( Collection < String > suiteNames , int slaves , long seed ) { // Read hints first. final Map < String , List < Long > > hints = ExecutionTimesReport . mergeHints ( resources , suiteNames ) ; // Preprocess and sort costs. Take the median for each suite's measurements as the // weight to avoid extreme measurements from screwing up the average. final List < SuiteHint > costs = new ArrayList <> ( ) ; for ( String suiteName : suiteNames ) { final List < Long > suiteHint = hints . get ( suiteName ) ; if ( suiteHint != null ) { // Take the median for each suite's measurements as the weight // to avoid extreme measurements from screwing up the average. Collections . sort ( suiteHint ) ; final Long median = suiteHint . get ( suiteHint . size ( ) / 2 ) ; costs . add ( new SuiteHint ( suiteName , median ) ) ; } } Collections . sort ( costs , SuiteHint . DESCENDING_BY_WEIGHT ) ; // Apply the assignment heuristic. final PriorityQueue < SlaveLoad > pq = new PriorityQueue < SlaveLoad > ( slaves , SlaveLoad . ASCENDING_BY_ESTIMATED_FINISH ) ; for ( int i = 0 ; i < slaves ; i ++ ) { pq . add ( new SlaveLoad ( i ) ) ; } final List < Assignment > assignments = new ArrayList <> ( ) ; for ( SuiteHint hint : costs ) { SlaveLoad slave = pq . remove ( ) ; slave . estimatedFinish += hint . cost ; pq . add ( slave ) ; owner . log ( "Expected execution time for " + hint . suiteName + ": " + Duration . toHumanDuration ( hint . cost ) , Project . MSG_DEBUG ) ; assignments . add ( new Assignment ( hint . suiteName , slave . id , ( int ) hint . cost ) ) ; } // Dump estimated execution times. TreeMap < Integer , SlaveLoad > ordered = new TreeMap < Integer , SlaveLoad > ( ) ; while ( ! pq . isEmpty ( ) ) { SlaveLoad slave = pq . remove ( ) ; ordered . put ( slave . id , slave ) ; } for ( Integer id : ordered . keySet ( ) ) { final SlaveLoad slave = ordered . get ( id ) ; owner . log ( String . format ( Locale . ROOT , "Expected execution time on JVM J%d: %8.2fs" , slave . id , slave . estimatedFinish / 1000.0f ) , verbose ? Project . MSG_INFO : Project . MSG_DEBUG ) ; } return assignments ; }
Assign based on execution time history . The algorithm is a greedy heuristic assigning the longest remaining test to the slave with the shortest - completion time so far . This is not optimal but fast and provides a decent average assignment .