160 lines
6.6 KiB
Java
160 lines
6.6 KiB
Java
package unit;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* SynapseTest — CWE-407 benchmark for synapse-0001 and synapse-0002
|
|
*
|
|
* synapse-0001: server_notices/resource_limits_server_notices.py
|
|
* `if event_id in referenced_events` + `referenced_events.remove()` inside for-loop
|
|
* Slow: List.contains + List.remove (both O(n)) called n times → O(n²)
|
|
* Fast: Set.contains + Set.remove → O(n)
|
|
*
|
|
* synapse-0002: handlers/sync.py
|
|
* `if user_id in user_ids_in_room` where user_ids_in_room is a Sequence[str] (List)
|
|
* Called inside loop over rooms; each room may have U members
|
|
* Slow: List.contains → O(U) per room, O(R*U) total
|
|
* Fast: Set.contains → O(1) per room, O(R+U) total
|
|
*
|
|
* compile: javac -d . SynapseTest.java && java -ea unit.SynapseTest
|
|
*/
|
|
public class SynapseTest {
|
|
|
|
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);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// synapse-0001: referenced_events List.remove in loop vs Set.discard
|
|
// -----------------------------------------------------------------------
|
|
|
|
/** Slow: List.contains + List.remove in loop — O(n²) */
|
|
static long slowServerNotices(int n) {
|
|
List<String> referencedEvents = new ArrayList<>();
|
|
for (int i = 0; i < n; i++) referencedEvents.add("event-" + i);
|
|
|
|
// Simulate: for event_id, event in events.items(): if event_id in referenced_events: remove
|
|
long ops = 0;
|
|
// half the events are ServerNoticeMsgType matches
|
|
List<String> toRemove = new ArrayList<>();
|
|
for (int i = 0; i < n; i += 2) toRemove.add("event-" + i);
|
|
|
|
for (String eventId : toRemove) {
|
|
ops += referencedEvents.size(); // cost of .contains() scan
|
|
if (referencedEvents.contains(eventId)) {
|
|
ops += referencedEvents.size(); // cost of .remove() scan + shift
|
|
referencedEvents.remove(eventId);
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
/** Fast: Set.discard — O(n) */
|
|
static long fastServerNotices(int n) {
|
|
Set<String> referencedSet = new LinkedHashSet<>();
|
|
for (int i = 0; i < n; i++) referencedSet.add("event-" + i);
|
|
|
|
long ops = 0;
|
|
List<String> toRemove = new ArrayList<>();
|
|
for (int i = 0; i < n; i += 2) toRemove.add("event-" + i);
|
|
|
|
for (String eventId : toRemove) {
|
|
ops += 1; // O(1) set remove
|
|
referencedSet.remove(eventId);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// synapse-0002: user_ids_in_room List linear scan vs Set
|
|
// -----------------------------------------------------------------------
|
|
|
|
/** Slow: List.contains for each room membership check — O(R * U) */
|
|
static long slowSyncUserInRoom(int numRooms, int usersPerRoom) {
|
|
long ops = 0;
|
|
String targetUser = "user-42";
|
|
for (int r = 0; r < numRooms; r++) {
|
|
// get_users_in_room returns a List
|
|
List<String> userList = new ArrayList<>();
|
|
for (int u = 0; u < usersPerRoom; u++) userList.add("user-" + u);
|
|
// if user_id in user_ids_in_room: O(U) scan
|
|
ops += userList.size(); // cost of linear scan
|
|
userList.contains(targetUser);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
/** Fast: frozenset lookup — O(R + U) */
|
|
static long fastSyncUserInRoom(int numRooms, int usersPerRoom) {
|
|
long ops = 0;
|
|
String targetUser = "user-42";
|
|
for (int r = 0; r < numRooms; r++) {
|
|
Set<String> userSet = new HashSet<>();
|
|
for (int u = 0; u < usersPerRoom; u++) userSet.add("user-" + u);
|
|
ops += 1; // O(1) set lookup
|
|
userSet.contains(targetUser);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("SynapseTest — CWE-407 benchmarks");
|
|
System.out.println();
|
|
|
|
int passed = 0;
|
|
int total = 0;
|
|
|
|
// --- synapse-0001 ---
|
|
int N_EVENTS = 2000;
|
|
long[] slowOps0001 = {0};
|
|
long[] fastOps0001 = {0};
|
|
|
|
Runnable slow0001 = () -> slowOps0001[0] = slowServerNotices(N_EVENTS);
|
|
Runnable fast0001 = () -> fastOps0001[0] = fastServerNotices(N_EVENTS);
|
|
|
|
// Pre-run to populate ops counts for display
|
|
slowOps0001[0] = slowServerNotices(N_EVENTS);
|
|
fastOps0001[0] = fastServerNotices(N_EVENTS);
|
|
bench("synapse-0001 server_notices List.remove vs Set.discard (n=" + N_EVENTS + ")",
|
|
slow0001, fast0001, slowOps0001[0], fastOps0001[0]);
|
|
|
|
total++;
|
|
if (slowOps0001[0] > fastOps0001[0] * 10L) {
|
|
System.out.println(" synapse-0001 PASS (slow ops=" + slowOps0001[0] + " > 10x fast ops=" + fastOps0001[0] + ")");
|
|
passed++;
|
|
} else {
|
|
System.out.println(" synapse-0001 FAIL (slow=" + slowOps0001[0] + " fast=" + fastOps0001[0] + ")");
|
|
}
|
|
assert slowOps0001[0] > fastOps0001[0] * 10L : "synapse-0001: slow ops not 10x fast ops";
|
|
|
|
// --- synapse-0002 ---
|
|
int NUM_ROOMS = 50;
|
|
int USERS_PER_ROOM = 5000;
|
|
long[] slowOps0002 = {0};
|
|
long[] fastOps0002 = {0};
|
|
|
|
Runnable slow0002 = () -> slowOps0002[0] = slowSyncUserInRoom(NUM_ROOMS, USERS_PER_ROOM);
|
|
Runnable fast0002 = () -> fastOps0002[0] = fastSyncUserInRoom(NUM_ROOMS, USERS_PER_ROOM);
|
|
|
|
slowOps0002[0] = slowSyncUserInRoom(NUM_ROOMS, USERS_PER_ROOM);
|
|
fastOps0002[0] = fastSyncUserInRoom(NUM_ROOMS, USERS_PER_ROOM);
|
|
bench("synapse-0002 sync user_in_room List vs Set (rooms=" + NUM_ROOMS + " users=" + USERS_PER_ROOM + ")",
|
|
slow0002, fast0002, slowOps0002[0], fastOps0002[0]);
|
|
|
|
total++;
|
|
if (slowOps0002[0] > fastOps0002[0] * 100L) {
|
|
System.out.println(" synapse-0002 PASS (slow ops=" + slowOps0002[0] + " > 100x fast ops=" + fastOps0002[0] + ")");
|
|
passed++;
|
|
} else {
|
|
System.out.println(" synapse-0002 FAIL (slow=" + slowOps0002[0] + " fast=" + fastOps0002[0] + ")");
|
|
}
|
|
assert slowOps0002[0] > fastOps0002[0] * 100L : "synapse-0002: slow ops not 100x fast ops";
|
|
|
|
System.out.println();
|
|
System.out.println(passed + "/" + total + " PASS");
|
|
}
|
|
}
|