130 lines
5.5 KiB
Java
130 lines
5.5 KiB
Java
package unit;
|
||
import java.util.*;
|
||
|
||
/**
|
||
* ElementWebTest — CWE-407 benchmark for element-web-0001
|
||
*
|
||
* element-web-0001: apps/web/src/TextForEvent.tsx:503
|
||
* textForPowerEvent() deduplicates user IDs from power level event using indexOf on an array.
|
||
* Two forEach loops each calling indexOf (O(n)) to build a dedup list — total O(N²).
|
||
*
|
||
* Slow: for each userId in contentUsers ∪ prevContentUsers: indexOf on accumulator array
|
||
* Fast: Set union in O(N)
|
||
*
|
||
* compile: javac -d . ElementWebTest.java && java -ea unit.ElementWebTest
|
||
*/
|
||
public class ElementWebTest {
|
||
|
||
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
|
||
slow.run(); fast.run(); // warmup
|
||
long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime() - t0) / 1_000_000;
|
||
long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime() - t1) / 1_000_000;
|
||
double ratio = fOps > 0 ? (double) sOps / fOps : 0;
|
||
System.out.printf(" %-60s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n",
|
||
label, sMs, sOps, fMs, fOps, ratio);
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// element-web-0001: users.indexOf dedup in forEach loop
|
||
// -----------------------------------------------------------------------
|
||
|
||
/**
|
||
* Slow: Array.indexOf inside forEach — O((A+B)²)
|
||
* Simulates building a dedup list from two sets of user IDs.
|
||
* Returns total comparison operations performed.
|
||
*/
|
||
static long slowPowerEventDedup(int contentUsers, int prevContentUsers) {
|
||
List<String> contentKeys = new ArrayList<>();
|
||
for (int i = 0; i < contentUsers; i++) contentKeys.add("user-" + i);
|
||
|
||
// prevContent has some overlap + some new users
|
||
List<String> prevKeys = new ArrayList<>();
|
||
for (int i = contentUsers / 2; i < contentUsers / 2 + prevContentUsers; i++)
|
||
prevKeys.add("user-" + i);
|
||
|
||
List<String> users = new ArrayList<>();
|
||
long ops = 0;
|
||
|
||
// forEach(userId => if (users.indexOf(userId) === -1) users.push(userId))
|
||
for (String userId : contentKeys) {
|
||
ops += users.size(); // cost of indexOf scan (grows as list fills)
|
||
if (!users.contains(userId)) users.add(userId);
|
||
}
|
||
for (String userId : prevKeys) {
|
||
ops += users.size(); // cost of indexOf scan
|
||
if (!users.contains(userId)) users.add(userId);
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/**
|
||
* Fast: Set union — O(A + B)
|
||
* Returns total operations (one per element).
|
||
*/
|
||
static long fastPowerEventDedup(int contentUsers, int prevContentUsers) {
|
||
List<String> contentKeys = new ArrayList<>();
|
||
for (int i = 0; i < contentUsers; i++) contentKeys.add("user-" + i);
|
||
|
||
List<String> prevKeys = new ArrayList<>();
|
||
for (int i = contentUsers / 2; i < contentUsers / 2 + prevContentUsers; i++)
|
||
prevKeys.add("user-" + i);
|
||
|
||
long ops = 0;
|
||
Set<String> userSet = new LinkedHashSet<>();
|
||
for (String u : contentKeys) { userSet.add(u); ops++; }
|
||
for (String u : prevKeys) { userSet.add(u); ops++; }
|
||
// Array.from(userSet) — O(N)
|
||
List<String> users = new ArrayList<>(userSet);
|
||
ops += users.size();
|
||
return ops;
|
||
}
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println("ElementWebTest — CWE-407 benchmarks");
|
||
System.out.println();
|
||
|
||
int passed = 0;
|
||
int total = 0;
|
||
|
||
// Small room (N=200 each side)
|
||
{
|
||
int A = 200, B = 200;
|
||
long[] sOps = {0}, fOps = {0};
|
||
Runnable s = () -> sOps[0] = slowPowerEventDedup(A, B);
|
||
Runnable f = () -> fOps[0] = fastPowerEventDedup(A, B);
|
||
sOps[0] = slowPowerEventDedup(A, B);
|
||
fOps[0] = fastPowerEventDedup(A, B);
|
||
bench("element-web-0001 power event dedup indexOf vs Set (A=" + A + " B=" + B + ")", s, f, sOps[0], fOps[0]);
|
||
total++;
|
||
if (sOps[0] > fOps[0] * 10L) {
|
||
System.out.println(" element-web-0001 small PASS (slow=" + sOps[0] + " > 10x fast=" + fOps[0] + ")");
|
||
passed++;
|
||
} else {
|
||
System.out.println(" element-web-0001 small FAIL (slow=" + sOps[0] + " fast=" + fOps[0] + ")");
|
||
}
|
||
assert sOps[0] > fOps[0] * 10L : "element-web-0001 small: slow ops not 10x fast ops";
|
||
}
|
||
|
||
// Large room (N=1000 each side — large server with many power level entries)
|
||
{
|
||
int A = 1000, B = 1000;
|
||
long[] sOps = {0}, fOps = {0};
|
||
Runnable s = () -> sOps[0] = slowPowerEventDedup(A, B);
|
||
Runnable f = () -> fOps[0] = fastPowerEventDedup(A, B);
|
||
sOps[0] = slowPowerEventDedup(A, B);
|
||
fOps[0] = fastPowerEventDedup(A, B);
|
||
bench("element-web-0001 power event dedup indexOf vs Set (A=" + A + " B=" + B + ")", s, f, sOps[0], fOps[0]);
|
||
total++;
|
||
if (sOps[0] > fOps[0] * 50L) {
|
||
System.out.println(" element-web-0001 large PASS (slow=" + sOps[0] + " > 50x fast=" + fOps[0] + ")");
|
||
passed++;
|
||
} else {
|
||
System.out.println(" element-web-0001 large FAIL (slow=" + sOps[0] + " fast=" + fOps[0] + ")");
|
||
}
|
||
assert sOps[0] > fOps[0] * 50L : "element-web-0001 large: slow ops not 50x fast ops";
|
||
}
|
||
|
||
System.out.println();
|
||
System.out.println(passed + "/" + total + " PASS");
|
||
}
|
||
}
|