@Override
 public int compare(Schedulable s1, Schedulable s2) {
   double minShareRatio1, minShareRatio2;
   double tasksToWeightRatio1, tasksToWeightRatio2;
   int minShare1 = Math.min(s1.getMinShare(), s1.getDemand());
   int minShare2 = Math.min(s2.getMinShare(), s2.getDemand());
   boolean s1Needy = s1.getRunningTasks() < minShare1;
   boolean s2Needy = s2.getRunningTasks() < minShare2;
   minShareRatio1 = s1.getRunningTasks() / Math.max(minShare1, 1.0);
   minShareRatio2 = s2.getRunningTasks() / Math.max(minShare2, 1.0);
   tasksToWeightRatio1 = s1.getRunningTasks() / s1.getWeight();
   tasksToWeightRatio2 = s2.getRunningTasks() / s2.getWeight();
   int res = 0;
   if (s1Needy && !s2Needy) res = -1;
   else if (s2Needy && !s1Needy) res = 1;
   else if (s1Needy && s2Needy) res = (int) Math.signum(minShareRatio1 - minShareRatio2);
   else // Neither schedulable is needy
   res = (int) Math.signum(tasksToWeightRatio1 - tasksToWeightRatio2);
   if (res == 0) {
     // Jobs are tied in fairness ratio. Break the tie by submit time and job
     // name to get a deterministic ordering, which is useful for unit tests.
     res = (int) Math.signum(s1.getStartTime() - s2.getStartTime());
     if (res == 0) res = s1.getName().compareTo(s2.getName());
   }
   return res;
 }
 /**
  * Given a set of Schedulables and a number of slots, compute their weighted fair shares. The min
  * shares and demands of the Schedulables are assumed to be set beforehand. We compute the fairest
  * possible allocation of shares to the Schedulables that respects their min shares and demands.
  *
  * <p>To understand what this method does, we must first define what weighted fair sharing means
  * in the presence of minimum shares and demands. If there were no minimum shares and every
  * Schedulable had an infinite demand (i.e. could launch infinitely many tasks), then weighted
  * fair sharing would be achieved if the ratio of slotsAssigned / weight was equal for each
  * Schedulable and all slots were assigned. Minimum shares and demands add two further twists: -
  * Some Schedulables may not have enough tasks to fill all their share. - Some Schedulables may
  * have a min share higher than their assigned share.
  *
  * <p>To deal with these possibilities, we define an assignment of slots as being fair if there
  * exists a ratio R such that: - Schedulables S where S.demand < R * S.weight are assigned share
  * S.demand - Schedulables S where S.minShare > R * S.weight are given share S.minShare - All
  * other Schedulables S are assigned share R * S.weight - The sum of all the shares is totalSlots.
  *
  * <p>We call R the weight-to-slots ratio because it converts a Schedulable's weight to the number
  * of slots it is assigned.
  *
  * <p>We compute a fair allocation by finding a suitable weight-to-slot ratio R. To do this, we
  * use binary search. Given a ratio R, we compute the number of slots that would be used in total
  * with this ratio (the sum of the shares computed using the conditions above). If this number of
  * slots is less than totalSlots, then R is too small and more slots could be assigned. If the
  * number of slots is more than totalSlots, then R is too large.
  *
  * <p>We begin the binary search with a lower bound on R of 0 (which means that all Schedulables
  * are only given their minShare) and an upper bound computed to be large enough that too many
  * slots are given (by doubling R until we either use more than totalSlots slots or we fulfill all
  * jobs' demands). The helper method slotsUsedWithWeightToSlotRatio computes the total number of
  * slots used with a given value of R.
  *
  * <p>The running time of this algorithm is linear in the number of Schedulables, because
  * slotsUsedWithWeightToSlotRatio is linear-time and the number of iterations of binary search is
  * a constant (dependent on desired precision).
  */
 public static void computeFairShares(
     Collection<? extends Schedulable> schedulables, double totalSlots) {
   // Find an upper bound on R that we can use in our binary search. We start
   // at R = 1 and double it until we have either used totalSlots slots or we
   // have met all Schedulables' demands (if total demand < totalSlots).
   double totalDemand = 0;
   for (Schedulable sched : schedulables) {
     totalDemand += sched.getDemand();
   }
   double cap = Math.min(totalDemand, totalSlots);
   double rMax = 1.0;
   while (slotsUsedWithWeightToSlotRatio(rMax, schedulables) < cap) {
     rMax *= 2.0;
   }
   // Perform the binary search for up to COMPUTE_FAIR_SHARES_ITERATIONS steps
   double left = 0;
   double right = rMax;
   for (int i = 0; i < COMPUTE_FAIR_SHARES_ITERATIONS; i++) {
     double mid = (left + right) / 2.0;
     if (slotsUsedWithWeightToSlotRatio(mid, schedulables) < cap) {
       left = mid;
     } else {
       right = mid;
     }
   }
   // Set the fair shares based on the value of R we've converged to
   for (Schedulable sched : schedulables) {
     sched.setFairShare(computeShare(sched, right));
   }
 }
 /**
  * Compute the number of slots assigned to a Schedulable given a particular weight-to-slot ratio
  * w2sRatio, for use in computeFairShares as described in #{@link
  * SchedulingAlgorithms#computeFairShares(Collection, double)}.
  */
 private static double computeShare(Schedulable sched, double w2sRatio) {
   double share = sched.getWeight() * w2sRatio;
   share = Math.max(share, sched.getMinShare());
   share = Math.min(share, sched.getDemand());
   return share;
 }