100 lines
3.2 KiB
Java
100 lines
3.2 KiB
Java
package unit;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* haproxy-0002: flt_spoe.c duplicate-name detection O(N²) vs O(N log N).
|
|
*
|
|
* slow: for each of N message names, walk the linked list of already-added
|
|
* names (strcmp per entry) — mirrors:
|
|
* while (*args[cur_arg]) {
|
|
* list_for_each_entry(ph, &curmphs, list)
|
|
* if (strcmp(ph->id, args[cur_arg]) == 0) ...
|
|
* }
|
|
*
|
|
* fast: pre-built HashSet; O(1) contains check per name.
|
|
*
|
|
* Assert: slowOps > fastOps * (N/2) for N=200 SPOE message names.
|
|
*/
|
|
public class HaproxySpoeAlgorithmTest {
|
|
|
|
static long slowOps;
|
|
static long fastOps;
|
|
|
|
// ---- slow: O(N²) linked-list duplicate detection (defect) ---------------
|
|
|
|
static List<String> slowAddMessages(String[] names) {
|
|
List<String> registered = new ArrayList<>();
|
|
for (String name : names) {
|
|
boolean dup = false;
|
|
for (String existing : registered) { // O(R) inner scan
|
|
slowOps++;
|
|
if (existing.equals(name)) {
|
|
dup = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!dup) {
|
|
registered.add(name);
|
|
}
|
|
}
|
|
return registered;
|
|
}
|
|
|
|
// ---- fast: O(N) HashSet duplicate detection (fix) -----------------------
|
|
|
|
static List<String> fastAddMessages(String[] names) {
|
|
List<String> registered = new ArrayList<>();
|
|
Set<String> seen = new HashSet<>();
|
|
for (String name : names) {
|
|
fastOps++; // O(1) HashSet lookup
|
|
if (!seen.contains(name)) {
|
|
seen.add(name);
|
|
registered.add(name);
|
|
}
|
|
}
|
|
return registered;
|
|
}
|
|
|
|
// ---- benchmark driver ---------------------------------------------------
|
|
|
|
public static void main(String[] args) {
|
|
final int N = 200; // SPOE message names in a single directive
|
|
|
|
// Generate N unique names (worst case: no duplicates = maximum list walks)
|
|
String[] names = new String[N];
|
|
for (int i = 0; i < N; i++) {
|
|
names[i] = "spoe-msg-" + i;
|
|
}
|
|
|
|
slowOps = 0;
|
|
fastOps = 0;
|
|
|
|
List<String> slowResult = slowAddMessages(names);
|
|
List<String> fastResult = fastAddMessages(names);
|
|
|
|
// Verify correctness: same number of unique entries
|
|
if (slowResult.size() != fastResult.size()) {
|
|
System.err.printf("FAIL: slow=%d entries fast=%d entries (mismatch)%n",
|
|
slowResult.size(), fastResult.size());
|
|
System.exit(1);
|
|
}
|
|
|
|
long ratio = slowOps / Math.max(fastOps, 1);
|
|
// Expect at least N/2 - 1 ratio since average list length = N/2
|
|
// (worst-case unique names: average walk = N/2, last entry walks N-1 steps)
|
|
boolean pass = slowOps > fastOps * (N / 2 - 2);
|
|
|
|
System.out.printf("haproxy-0002 slow=%d fast=%d ratio=%dx %s%n",
|
|
slowOps, fastOps, ratio, pass ? "PASS" : "FAIL");
|
|
|
|
if (!pass) {
|
|
System.err.printf("FAIL: expected slowOps(%d) > fastOps(%d) * %d%n",
|
|
slowOps, fastOps, N / 2 - 2);
|
|
System.exit(1);
|
|
}
|
|
}
|
|
}
|