java-topology/defects/xen/unit/Xen0001CreditBalanceLoadAlgorithm.java

187 lines
6.9 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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:28352861).
* 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<Vcpu> lrqdSvc, List<Vcpu> 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<Vcpu> lrqdSvcSorted,
List<Vcpu> 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<Vcpu> buildSvcList(int count, long baseLoad, boolean sorted) {
List<Vcpu> 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<Vcpu> 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<Vcpu> lrqd = buildSvcList(v, 100, false);
List<Vcpu> orqd = buildSvcList(v, 50, false);
long lLoad = totalLoad(lrqd);
long oLoad = totalLoad(orqd);
defective.findBestSwap(lrqd, orqd, lLoad, oLoad);
int defectOps = defective.comparisons;
List<Vcpu> lrqdSorted = buildSvcList(v, 100, true);
List<Vcpu> 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);
}
}
}