wave17 complete: systemd/emacs/vim/qemu/tcl/kafka-0007/spark-0004 + 559/240
This commit is contained in:
parent
4221966e66
commit
cce7ec653a
32 changed files with 3007 additions and 5 deletions
174
defects/qemu/unit/QemuSavevmFindSeAlgorithm.java
Normal file
174
defects/qemu/unit/QemuSavevmFindSeAlgorithm.java
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* qemu-0001: find_se() O(N²) during migration load
|
||||
*
|
||||
* Models QEMU's savevm handler registry and find_se() lookup.
|
||||
* SLOW: linear scan of handler list per lookup (current QEMU code)
|
||||
* FAST: hash map keyed by (idstr, instance_id) (proposed fix)
|
||||
*
|
||||
* During VM load, qemu_loadvm_state_main() calls qemu_loadvm_section_start_full()
|
||||
* for each of the N sections in the migration stream. Each call invokes find_se(),
|
||||
* which does an O(N) linear scan. Total: O(N²).
|
||||
*/
|
||||
public class QemuSavevmFindSeAlgorithm {
|
||||
|
||||
// --- Data model ---
|
||||
|
||||
static class SaveStateEntry {
|
||||
String idstr;
|
||||
int instanceId;
|
||||
|
||||
SaveStateEntry(String idstr, int instanceId) {
|
||||
this.idstr = idstr;
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
}
|
||||
|
||||
// --- SLOW: linear scan (current QEMU find_se) ---
|
||||
|
||||
static class SlowRegistry {
|
||||
List<SaveStateEntry> handlers = new ArrayList<>();
|
||||
long opCount = 0;
|
||||
|
||||
void register(String idstr, int instanceId) {
|
||||
handlers.add(new SaveStateEntry(idstr, instanceId));
|
||||
}
|
||||
|
||||
SaveStateEntry findSe(String idstr, int instanceId) {
|
||||
for (SaveStateEntry se : handlers) {
|
||||
opCount++;
|
||||
if (se.idstr.equals(idstr) && se.instanceId == instanceId) {
|
||||
return se;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Simulate loading N sections from a migration stream */
|
||||
int loadSections() {
|
||||
int found = 0;
|
||||
for (SaveStateEntry target : handlers) {
|
||||
SaveStateEntry se = findSe(target.idstr, target.instanceId);
|
||||
if (se != null) found++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
// --- FAST: hash map (proposed fix) ---
|
||||
|
||||
static class FastRegistry {
|
||||
List<SaveStateEntry> handlers = new ArrayList<>();
|
||||
Map<String, SaveStateEntry> handlerMap = new HashMap<>();
|
||||
long opCount = 0;
|
||||
|
||||
static String makeKey(String idstr, int instanceId) {
|
||||
return idstr + ":" + instanceId;
|
||||
}
|
||||
|
||||
void register(String idstr, int instanceId) {
|
||||
SaveStateEntry se = new SaveStateEntry(idstr, instanceId);
|
||||
handlers.add(se);
|
||||
handlerMap.put(makeKey(idstr, instanceId), se);
|
||||
}
|
||||
|
||||
SaveStateEntry findSe(String idstr, int instanceId) {
|
||||
opCount++;
|
||||
return handlerMap.get(makeKey(idstr, instanceId));
|
||||
}
|
||||
|
||||
/** Simulate loading N sections from a migration stream */
|
||||
int loadSections() {
|
||||
int found = 0;
|
||||
for (SaveStateEntry target : handlers) {
|
||||
SaveStateEntry se = findSe(target.idstr, target.instanceId);
|
||||
if (se != null) found++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test harness ---
|
||||
|
||||
static int passed = 0;
|
||||
static int total = 0;
|
||||
|
||||
static void check(String name, boolean cond) {
|
||||
total++;
|
||||
if (cond) {
|
||||
passed++;
|
||||
System.out.println(" PASS: " + name);
|
||||
} else {
|
||||
System.out.println(" FAIL: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== qemu-0001: find_se O(N^2) during migration load ===");
|
||||
|
||||
// Build registry of N vmstate handlers (virtio devices, CPUs, PCI, RAM)
|
||||
int N = 500;
|
||||
SlowRegistry slow = new SlowRegistry();
|
||||
FastRegistry fast = new FastRegistry();
|
||||
|
||||
// Register N distinct handlers with various idstrs
|
||||
for (int i = 0; i < N; i++) {
|
||||
String idstr = "device-" + (i % 50); // 50 unique device types
|
||||
int instanceId = i / 50; // up to 10 instances per type
|
||||
slow.register(idstr, instanceId);
|
||||
fast.register(idstr, instanceId);
|
||||
}
|
||||
|
||||
// Correctness: both find the same entries
|
||||
int slowFound = slow.loadSections();
|
||||
int fastFound = fast.loadSections();
|
||||
|
||||
check("slow finds all " + N + " handlers", slowFound == N);
|
||||
check("fast finds all " + N + " handlers", fastFound == N);
|
||||
check("slow and fast agree", slowFound == fastFound);
|
||||
|
||||
// Specific lookup
|
||||
SaveStateEntry slowSe = slow.findSe("device-0", 0);
|
||||
SaveStateEntry fastSe = fast.findSe("device-0", 0);
|
||||
check("slow finds device-0:0", slowSe != null);
|
||||
check("fast finds device-0:0", fastSe != null);
|
||||
|
||||
SaveStateEntry slowMiss = slow.findSe("nonexistent", 99);
|
||||
SaveStateEntry fastMiss = fast.findSe("nonexistent", 99);
|
||||
check("slow returns null for unknown", slowMiss == null);
|
||||
check("fast returns null for unknown", fastMiss == null);
|
||||
|
||||
// Reset opcount before load simulation
|
||||
slow.opCount = 0;
|
||||
fast.opCount = 0;
|
||||
slow.loadSections();
|
||||
fast.loadSections();
|
||||
|
||||
long slowOps = slow.opCount;
|
||||
long fastOps = fast.opCount;
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
|
||||
System.out.println();
|
||||
System.out.println("N=" + N + " handlers, loading N sections from migration stream:");
|
||||
System.out.printf(" SLOW ops (linear scan): %,d%n", slowOps);
|
||||
System.out.printf(" FAST ops (hash lookup): %,d%n", fastOps);
|
||||
System.out.printf(" Ratio: %.1fx%n", ratio);
|
||||
|
||||
check("slow is O(N^2): ops >= N*(N/4)", slowOps >= (long) N * N / 4);
|
||||
check("fast is O(N): ops <= N*2", fastOps <= (long) N * 2);
|
||||
check("ratio >= 5x", ratio >= 5.0);
|
||||
|
||||
System.out.println();
|
||||
System.out.println(passed + "/" + total + " PASS");
|
||||
|
||||
if (passed != total) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue