java-topology/defects/pulsar/unit/PulsarPartialRoundRobinRouterTest.java

90 lines
2.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 unit;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* pulsar-0005 — PartialRoundRobinMessageRouterImpl CopyOnWriteArrayList.contains O(N×L) → HashSet O(N)
*
* The hot path in getOrCreatePartialList() is the filter lambda:
* .filter(e -> !partialList.contains(e))
*
* This benchmark isolates the membership test — N calls to contains()
* over a CopyOnWriteArrayList of size L vs a HashSet snapshot.
*
* SLOW: CopyOnWriteArrayList.contains(e) → O(L) per call → O(N × L) total
* FAST: HashSet.contains(e) → O(1) per call → O(N) total
*/
public class PulsarPartialRoundRobinRouterTest {
static long benchSlow(int N, int L) {
CopyOnWriteArrayList<Integer> partialList = new CopyOnWriteArrayList<>();
for (int i = 0; i < L; i++) {
partialList.add(i * 2); // even indices present
}
long start = System.nanoTime();
int found = 0;
for (int i = 0; i < N; i++) {
if (!partialList.contains(i)) found++; // O(L) per call
}
return System.nanoTime() - start;
}
static long benchFast(int N, int L) {
CopyOnWriteArrayList<Integer> partialList = new CopyOnWriteArrayList<>();
for (int i = 0; i < L; i++) {
partialList.add(i * 2);
}
// FIX: snapshot to HashSet before the filter loop
Set<Integer> existing = new HashSet<>(partialList);
long start = System.nanoTime();
int found = 0;
for (int i = 0; i < N; i++) {
if (!existing.contains(i)) found++; // O(1) per call
}
return System.nanoTime() - start;
}
public static void main(String[] args) {
int passed = 0;
int failed = 0;
int minRatio = 5;
// [N = numPartitions, L = partialList.size() at expand time]
int[][] cases = {
{500, 250},
{2000, 1000},
{5000, 2500},
};
// warmup
for (int w = 0; w < 3; w++) {
benchSlow(200, 100);
benchFast(200, 100);
}
for (int[] c : cases) {
int N = c[0];
int L = c[1];
long slowTotal = 0, fastTotal = 0;
int reps = 10;
for (int r = 0; r < reps; r++) {
slowTotal += benchSlow(N, L);
fastTotal += benchFast(N, L);
}
long slowAvg = slowTotal / reps;
long fastAvg = fastTotal / reps;
double ratio = fastAvg > 0 ? (double) slowAvg / fastAvg : 999.0;
boolean ok = ratio >= minRatio;
System.out.printf(" N=%-5d L=%-5d slow=%8dns fast=%7dns ratio=%.1fx %s%n",
N, L, slowAvg, fastAvg, ratio, ok ? "PASS" : "FAIL");
if (ok) passed++; else failed++;
}
System.out.printf("%nTotal: %d/%d PASS%n", passed, passed + failed);
if (failed > 0) System.exit(1);
}
}