wave17 complete: systemd/emacs/vim/qemu/tcl/kafka-0007/spark-0004 + 559/240

This commit is contained in:
russell@unturf.com 2026-03-27 20:15:47 -04:00
parent 4221966e66
commit cce7ec653a
32 changed files with 3007 additions and 5 deletions

View file

@ -0,0 +1,188 @@
package unit;
import java.util.*;
/**
* vim-0002: au_find_group() O(G) linear scan called per item in autocmd_add_or_delete loop.
*
* Models autocmd_add_or_delete() iterating over L list items and calling
* au_find_group() (O(G) scan over augroups array) for each.
* Total work: O(L×G).
*
* The fix uses a HashMap<name, index> for O(1) group lookup.
*/
public class AuFindGroupTest {
// ----- SLOW path: linear scan over augroups array (mirrors Vim's autocmd.c) -----
static int auFindGroupSlow(String[] augroups, String name, long[] ops) {
for (int i = 0; i < augroups.length; i++) {
ops[0]++;
if (augroups[i] != null && augroups[i].equals(name)) {
return i;
}
}
return -1; // AUGROUP_ERROR
}
static long slowAutocmdAddOrDelete(String[] augroups, String[] listGroupNames) {
long[] ops = {0};
for (String groupName : listGroupNames) {
// au_find_group() call per list item
int group = auFindGroupSlow(augroups, groupName, ops);
if (group == -1) {
// au_new_group also calls au_find_group first (already counted above)
// then does another scan for a free slot
for (int i = 0; i < augroups.length; i++) {
ops[0]++;
if (augroups[i] == null) break;
}
}
}
return ops[0];
}
// ----- FAST path: HashMap<name, index> lookup -----
static long fastAutocmdAddOrDelete(Map<String, Integer> augroupsMap, String[] listGroupNames) {
long ops = 0;
for (String groupName : listGroupNames) {
ops++; // O(1) hash lookup
augroupsMap.get(groupName); // may return null (group not found)
}
return ops;
}
// ----- Helpers -----
static String[] buildAugroups(int G) {
String[] augroups = new String[G];
for (int i = 0; i < G; i++) augroups[i] = "group_" + i;
return augroups;
}
static Map<String, Integer> buildAugroupsMap(int G) {
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i < G; i++) map.put("group_" + i, i);
return map;
}
static String[] buildListItems(int L, int G) {
// Each list item references a random group from the pool
String[] items = new String[L];
for (int i = 0; i < L; i++) items[i] = "group_" + (i % G);
return items;
}
// ----- Test runner -----
public static void main(String[] args) {
System.out.println("vim-0002: AuFindGroupTest");
System.out.println("========================");
int passed = 0;
int total = 0;
// Test 1: correctness — both paths resolve the same group indices
{
total++;
int G = 10;
String[] augroups = buildAugroups(G);
Map<String, Integer> augroupsMap = buildAugroupsMap(G);
String[] queries = {"group_0", "group_5", "group_9", "group_99"};
boolean ok = true;
long[] ops = {0};
for (String q : queries) {
int slowResult = auFindGroupSlow(augroups, q, ops);
Integer fastResult = augroupsMap.get(q);
int fastInt = (fastResult == null) ? -1 : fastResult;
if (slowResult != fastInt) { ok = false; break; }
}
System.out.println("Test 1 (correctness): " + (ok ? "PASS" : "FAIL"));
if (ok) passed++;
}
// Test 2: op-count ratio >= 5x at L=100, G=20
{
total++;
int L = 100, G = 20;
String[] augroups = buildAugroups(G);
Map<String, Integer> augroupsMap = buildAugroupsMap(G);
String[] listItems = buildListItems(L, G);
long slowOps = slowAutocmdAddOrDelete(augroups, listItems);
long fastOps = fastAutocmdAddOrDelete(augroupsMap, listItems);
double ratio = (double) slowOps / fastOps;
System.out.printf("Test 2 (L=%d, G=%d): slow=%d ops, fast=%d ops, ratio=%.1fx%n",
L, G, slowOps, fastOps, ratio);
boolean ok = ratio >= 5.0;
System.out.println("Test 2 (ratio >= 5x): " + (ok ? "PASS" : "FAIL"));
if (ok) passed++;
}
// Test 3: op-count ratio >= 50x at L=500, G=100
{
total++;
int L = 500, G = 100;
String[] augroups = buildAugroups(G);
Map<String, Integer> augroupsMap = buildAugroupsMap(G);
String[] listItems = buildListItems(L, G);
long slowOps = slowAutocmdAddOrDelete(augroups, listItems);
long fastOps = fastAutocmdAddOrDelete(augroupsMap, listItems);
double ratio = (double) slowOps / fastOps;
System.out.printf("Test 3 (L=%d, G=%d): slow=%d ops, fast=%d ops, ratio=%.1fx%n",
L, G, slowOps, fastOps, ratio);
boolean ok = ratio >= 50.0;
System.out.println("Test 3 (ratio >= 50x): " + (ok ? "PASS" : "FAIL"));
if (ok) passed++;
}
// Test 4: op-count ratio >= 80x at L=500, G=100, all distinct group names
{
total++;
int L = 500, G = 100;
String[] augroups = buildAugroups(G);
Map<String, Integer> augroupsMap = buildAugroupsMap(G);
// Each item references a distinct group — worst case for linear scan
// when group is not found (searches entire array each time)
String[] listItems = new String[L];
for (int i = 0; i < L; i++) listItems[i] = "missing_group_" + i;
long slowOps = slowAutocmdAddOrDelete(augroups, listItems);
long fastOps = fastAutocmdAddOrDelete(augroupsMap, listItems);
double ratio = (double) slowOps / fastOps;
System.out.printf("Test 4 (L=%d, G=%d, all-miss): slow=%d ops, fast=%d ops, ratio=%.1fx%n",
L, G, slowOps, fastOps, ratio);
boolean ok = ratio >= 80.0;
System.out.println("Test 4 (ratio >= 80x): " + (ok ? "PASS" : "FAIL"));
if (ok) passed++;
}
// Test 5: op-count ratio >= 5x at small scale L=50, G=10
{
total++;
int L = 50, G = 10;
String[] augroups = buildAugroups(G);
Map<String, Integer> augroupsMap = buildAugroupsMap(G);
String[] listItems = buildListItems(L, G);
long slowOps = slowAutocmdAddOrDelete(augroups, listItems);
long fastOps = fastAutocmdAddOrDelete(augroupsMap, listItems);
double ratio = (double) slowOps / fastOps;
System.out.printf("Test 5 (L=%d, G=%d): slow=%d ops, fast=%d ops, ratio=%.1fx%n",
L, G, slowOps, fastOps, ratio);
boolean ok = ratio >= 5.0;
System.out.println("Test 5 (ratio >= 5x): " + (ok ? "PASS" : "FAIL"));
if (ok) passed++;
}
System.out.println();
System.out.println(passed + "/" + total + " PASS");
assert passed == total : passed + "/" + total + " tests passed";
}
}