package defects.xen.unit; import java.util.*; /** * xen-0001: Xen credit2 balance_load() O(V²) VCPU swap-search. * * Models the inner double-loop in balance_load() (credit2.c:2835–2861). * The defective version iterates all VCPUs on lrqd × orqd to find the best * (push, pull) swap pair. The fixed version maintains runqueue lists sorted * by avgload so the best pair is found in O(V) time. */ public class Xen0001CreditBalanceLoadAlgorithm { public static class Vcpu { final int id; long avgload; boolean migratable; Vcpu(int id, long avgload, boolean migratable) { this.id = id; this.avgload = avgload; this.migratable = migratable; } } public static class SwapPair { final Vcpu push; // from lrqd final Vcpu pull; // from orqd (may be null for push-only) final long loadDelta; // abs delta after swap SwapPair(Vcpu push, Vcpu pull, long loadDelta) { this.push = push; this.pull = pull; this.loadDelta = loadDelta; } } // ----------------------------------------------------------------------- // Defective: O(V²) — full cross-product as in credit2.c // ----------------------------------------------------------------------- public static class DefectiveBalanceLoad { public int comparisons; public SwapPair findBestSwap(List lrqdSvc, List orqdSvc, long lLoad, long oLoad) { comparisons = 0; SwapPair best = null; long bestDelta = Math.abs(lLoad - oLoad); for (Vcpu push : lrqdSvc) { if (!push.migratable) continue; for (Vcpu pull : orqdSvc) { comparisons++; if (!pull.migratable) continue; // delta after swapping push→orqd and pull→lrqd long newL = lLoad - push.avgload + pull.avgload; long newO = oLoad - pull.avgload + push.avgload; long delta = Math.abs(newL - newO); if (delta < bestDelta) { bestDelta = delta; best = new SwapPair(push, pull, delta); } } // push-only consideration long newL = lLoad - push.avgload; long newO = oLoad + push.avgload; long delta = Math.abs(newL - newO); if (delta < bestDelta) { bestDelta = delta; best = new SwapPair(push, null, delta); } } return best; } } // ----------------------------------------------------------------------- // Fixed: O(V) — pick heaviest push + lightest pull from sorted lists // ----------------------------------------------------------------------- public static class FixedBalanceLoad { public int comparisons; /** * Both lrqdSvc and orqdSvc are assumed sorted descending by avgload * (maintained at VCPU assign/weight-update time). * Scan from highest-weight end for push, lowest-weight end for pull. */ public SwapPair findBestSwap(List lrqdSvcSorted, List orqdSvcSorted, long lLoad, long oLoad) { comparisons = 0; long currentDelta = Math.abs(lLoad - oLoad); // Find heaviest migratable push candidate Vcpu bestPush = null; for (Vcpu v : lrqdSvcSorted) { comparisons++; if (v.migratable) { bestPush = v; break; } } if (bestPush == null) return null; // Find lightest migratable pull candidate (from end of sorted list) Vcpu bestPull = null; for (int i = orqdSvcSorted.size() - 1; i >= 0; i--) { comparisons++; Vcpu v = orqdSvcSorted.get(i); if (v.migratable) { bestPull = v; break; } } // Evaluate push+pull swap SwapPair best = null; if (bestPull != null) { long newL = lLoad - bestPush.avgload + bestPull.avgload; long newO = oLoad - bestPull.avgload + bestPush.avgload; long delta = Math.abs(newL - newO); if (delta < currentDelta) { best = new SwapPair(bestPush, bestPull, delta); currentDelta = delta; } } // Evaluate push-only long newL = lLoad - bestPush.avgload; long newO = oLoad + bestPush.avgload; long delta = Math.abs(newL - newO); if (delta < currentDelta) { best = new SwapPair(bestPush, null, delta); } return best; } } // ----------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------- /** Build a list of V VCPUs with loads evenly spread, all migratable. */ public static List buildSvcList(int count, long baseLoad, boolean sorted) { List list = new ArrayList<>(); for (int i = 0; i < count; i++) { list.add(new Vcpu(i, baseLoad + i * 10, true)); } if (sorted) { list.sort((a, b) -> Long.compare(b.avgload, a.avgload)); } return list; } /** Compute total load for a VCPU list. */ public static long totalLoad(List svc) { return svc.stream().mapToLong(v -> v.avgload).sum(); } public static void main(String[] args) { System.out.println("xen-0001: credit2 balance_load O(V^2) vs O(V)"); System.out.println("=".repeat(55)); int[] sizes = {10, 50, 100, 200}; DefectiveBalanceLoad defective = new DefectiveBalanceLoad(); FixedBalanceLoad fixed = new FixedBalanceLoad(); System.out.printf("%-8s %-12s %-12s %-8s%n", "V/rqd", "Defect ops", "Fixed ops", "Ratio"); for (int v : sizes) { List lrqd = buildSvcList(v, 100, false); List orqd = buildSvcList(v, 50, false); long lLoad = totalLoad(lrqd); long oLoad = totalLoad(orqd); defective.findBestSwap(lrqd, orqd, lLoad, oLoad); int defectOps = defective.comparisons; List lrqdSorted = buildSvcList(v, 100, true); List orqdSorted = buildSvcList(v, 50, true); fixed.findBestSwap(lrqdSorted, orqdSorted, lLoad, oLoad); int fixedOps = fixed.comparisons; double ratio = (double) defectOps / fixedOps; System.out.printf("%-8d %-12d %-12d %.1f×%n", v, defectOps, fixedOps, ratio); } } }