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
188
defects/vim/unit/AuFindGroupTest.java
Normal file
188
defects/vim/unit/AuFindGroupTest.java
Normal 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";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue