whitepaper: 398/185 — wave6d (rails-0012..16, jsc-0001/2, vtk, sm-0002, redis/valkey-0003, helm-0002/3, k8s-0003)

This commit is contained in:
russell@unturf.com 2026-03-27 15:57:50 -04:00
parent eb9612e4bf
commit 3735145aa5
47 changed files with 3488 additions and 33 deletions

View file

@ -0,0 +1,382 @@
package unit;
import java.util.*;
/**
* Linux0005Test CWE-407 benchmark for linux-0005 and linux-0006
*
* linux-0005 (COMPONENT_FIND_QUADRATIC):
* Models drivers/base/component.c find_components():
* SLOW: for each adev [O(A)]:
* for each match entry [O(M)]:
* find_component() scans component_list [O(C)]
* Total: O(A × M × C) per component_add()
* With N component_add() calls at boot: O(N × A × M × C) = O(N²) boot cost
* FAST: hash table keyed on dev pointer O(1) lookup
* Total per component_add(): O(A × M)
*
* linux-0006 (BTF_MODULE_SCAN_LINEAR):
* Models kernel/bpf/btf.c bpf_find_btf_id():
* SLOW: idr_for_each_entry() scans all loaded module BTFs [O(M)] per kptr field
* A BPF map struct with F kptr fields O(F × M) per BPF_MAP_CREATE syscall
* Kernel comment: "linear search could be slow"
* FAST: hash table keyed on (name_hash ^ kind) O(1) amortised after first miss
* O(F) per BPF_MAP_CREATE after cache warm-up
*/
public class Linux0005Test {
// =========================================================================
// linux-0005: component find_components O(A×M×C) vs O(A×M)
// =========================================================================
/** Simulates struct component — one registered device component. */
static class Component {
final Object dev; // device pointer (any Object we use identity)
Object boundAdev; // null if unbound
Component(Object dev) { this.dev = dev; }
}
/** One entry in a match array — holds the dev pointer to find. */
static class MatchEntry {
final Object devWanted; // the device this entry is looking for
Component component; // filled in when found
MatchEntry(Object devWanted) { this.devWanted = devWanted; }
}
/** Simulates struct aggregate_device. */
static class AggDev {
final MatchEntry[] match;
AggDev(MatchEntry[] match) { this.match = match; }
}
/**
* SLOW: find_component() O(C) linear scan of component_list.
* Returns number of comparisons performed.
*/
static long findComponent_slow(List<Component> componentList,
AggDev adev,
MatchEntry mc) {
long ops = 0;
for (Component c : componentList) {
ops++;
if (c.boundAdev != null && c.boundAdev != adev)
continue;
// mc->compare(c->dev, mc->data) identity comparison
if (c.dev == mc.devWanted) {
return ops;
}
}
return ops;
}
/**
* SLOW: find_components() calls find_component() M times per adev.
* Outer loop over adevs: O(A × M × C).
* Returns total comparison count.
*/
static long findComponents_slow(List<Component> componentList,
List<AggDev> adevList) {
long ops = 0;
for (AggDev adev : adevList) {
for (MatchEntry mc : adev.match) {
if (mc.component != null) continue;
ops += findComponent_slow(componentList, adev, mc);
}
}
return ops;
}
/**
* FAST: hash table (IdentityHashMap as O(1) lookup) keyed on dev pointer.
* find_component() becomes a single map.get() call.
* Returns total comparison count (always 1 per match entry for a hit).
*/
static long findComponents_fast(Map<Object, Component> componentMap,
List<AggDev> adevList) {
long ops = 0;
for (AggDev adev : adevList) {
for (MatchEntry mc : adev.match) {
if (mc.component != null) continue;
ops++; // one hash probe
Component c = componentMap.get(mc.devWanted);
if (c != null && (c.boundAdev == null || c.boundAdev == adev)) {
// found
}
}
}
return ops;
}
// =========================================================================
// linux-0006: bpf_find_btf_id O(F×M) vs O(F) with cache
// =========================================================================
/** Simulates one module BTF — holds a flat array of type names. */
static class ModuleBtf {
final String moduleName;
final String[] typeNames;
ModuleBtf(String moduleName, String[] typeNames) {
this.moduleName = moduleName;
this.typeNames = typeNames;
}
/** O(T) linear scan — btf_find_by_name_kind for module BTF. */
int findByNameKind(String name, int kind) {
for (int i = 0; i < typeNames.length; i++) {
if (typeNames[i].equals(name)) return i + 1; // positive id
}
return -1;
}
}
/**
* SLOW: bpf_find_btf_id() idr_for_each_entry over all module BTFs.
* For each kptr field: scan M module BTFs O(F × M × T).
* Returns number of (module-BTF, field) scan iterations.
*/
static long findBtfId_slow(List<ModuleBtf> moduleBtfs,
String[] kptrFieldNames,
int kind) {
long ops = 0;
for (String fieldName : kptrFieldNames) {
// idr_for_each_entry walks all M module BTFs
for (ModuleBtf mbtf : moduleBtfs) {
ops++;
int id = mbtf.findByNameKind(fieldName, kind);
if (id > 0) break; // found stop scanning
}
}
return ops;
}
/**
* FAST: nameid hash cache (HashMap as O(1) lookup).
* First lookup for a name misses and populates the cache; subsequent
* lookups are O(1). Returns total module-BTF iterations across all fields.
*
* Simulates: check vmlinux (O(log T) bsearch, modelled as O(1)),
* then check cache (O(1)), then fall through to O(M) scan on miss.
*/
static long findBtfId_fast(List<ModuleBtf> moduleBtfs,
String[] kptrFieldNames,
int kind,
Map<String, Integer> cache) {
long ops = 0;
for (String fieldName : kptrFieldNames) {
String cacheKey = fieldName + ":" + kind;
if (cache.containsKey(cacheKey)) {
ops++; // O(1) cache hit
continue;
}
// Cache miss scan modules (first time only)
for (ModuleBtf mbtf : moduleBtfs) {
ops++;
int id = mbtf.findByNameKind(fieldName, kind);
if (id > 0) {
cache.put(cacheKey, id); // populate cache
break;
}
}
}
return ops;
}
// =========================================================================
// Harness
// =========================================================================
static void bench(String label, long sOps, long fOps, long minRatio) {
double ratio = fOps == 0 ? Double.MAX_VALUE : (double) sOps / fOps;
boolean pass = ratio >= minRatio;
System.out.printf(" %-60s slow=%,d fast=%,d ratio=%.1fx [%s]%n",
label, sOps, fOps, ratio, pass ? "PASS" : "FAIL");
}
// =========================================================================
// main
// =========================================================================
public static void main(String[] args) {
int passed = 0, total = 0;
System.out.println("Linux0005Test — CWE-407 (linux-0005 component, linux-0006 btf)");
System.out.println("=".repeat(76));
// ------------------------------------------------------------------
// linux-0005: component find_components quadratic
// ------------------------------------------------------------------
System.out.println("\nlinux-0005: component find_components O(A×M×C) vs O(A×M)");
{
// Realistic SoC: 80 components, 6 aggregate devices, 8 match entries each
int C = 80, A = 6, M = 8;
List<Object> devPtrs = new ArrayList<>(C);
for (int i = 0; i < C; i++) devPtrs.add(new Object());
List<Component> componentList = new ArrayList<>(C);
Map<Object, Component> componentMap = new IdentityHashMap<>(C * 2);
for (Object dev : devPtrs) {
Component comp = new Component(dev);
componentList.add(comp);
componentMap.put(dev, comp);
}
// Each adev matches the last M devices (worst-case: found at end of list)
List<AggDev> adevList = new ArrayList<>(A);
for (int a = 0; a < A; a++) {
MatchEntry[] matches = new MatchEntry[M];
for (int m = 0; m < M; m++) {
// Point at tail of the component list worst case for linear scan
matches[m] = new MatchEntry(devPtrs.get(C - 1 - m));
}
adevList.add(new AggDev(matches));
}
// Simulate N component_add() events each triggers find_components on all adevs
int N = 80;
long slowTotal = 0, fastTotal = 0;
for (int n = 0; n < N; n++) {
// Clear bound state so all matches are re-evaluated
for (AggDev ad : adevList)
for (MatchEntry me : ad.match) me.component = null;
slowTotal += findComponents_slow(componentList, adevList);
}
for (int n = 0; n < N; n++) {
for (AggDev ad : adevList)
for (MatchEntry me : ad.match) me.component = null;
fastTotal += findComponents_fast(componentMap, adevList);
}
// Expected: slow = N × A × M × avg_scan = 80 × 6 × 8 × ~(C/2) 153600
// fast = N × A × M × 1 = 80 × 6 × 8 = 3840
// Ratio C/2 = 40x
long expectedMinRatio = Math.max(5L, (long)(C / 4));
bench(String.format("SoC boot C=%d A=%d M=%d N=%d component_add events", C, A, M, N),
slowTotal, fastTotal, expectedMinRatio);
total++;
if (slowTotal > fastTotal * expectedMinRatio) passed++;
}
{
// Large display controller: 200 components, 12 adevs, 15 match entries
int C = 200, A = 12, M = 15;
List<Object> devPtrs = new ArrayList<>(C);
for (int i = 0; i < C; i++) devPtrs.add(new Object());
List<Component> componentList = new ArrayList<>(C);
Map<Object, Component> componentMap = new IdentityHashMap<>(C * 2);
for (Object dev : devPtrs) {
Component comp = new Component(dev);
componentList.add(comp);
componentMap.put(dev, comp);
}
List<AggDev> adevList = new ArrayList<>(A);
for (int a = 0; a < A; a++) {
MatchEntry[] matches = new MatchEntry[M];
for (int m = 0; m < M; m++)
matches[m] = new MatchEntry(devPtrs.get(C - 1 - m));
adevList.add(new AggDev(matches));
}
int N = 200;
long slowTotal = 0, fastTotal = 0;
for (int n = 0; n < N; n++) {
for (AggDev ad : adevList)
for (MatchEntry me : ad.match) me.component = null;
slowTotal += findComponents_slow(componentList, adevList);
}
for (int n = 0; n < N; n++) {
for (AggDev ad : adevList)
for (MatchEntry me : ad.match) me.component = null;
fastTotal += findComponents_fast(componentMap, adevList);
}
long expectedMinRatio = Math.max(5L, (long)(C / 4));
bench(String.format("Display ctrl C=%d A=%d M=%d N=%d component_add events", C, A, M, N),
slowTotal, fastTotal, expectedMinRatio);
total++;
if (slowTotal > fastTotal * expectedMinRatio) passed++;
}
// ------------------------------------------------------------------
// linux-0006: bpf_find_btf_id O(F×M) vs O(F) with cache
// ------------------------------------------------------------------
System.out.println("\nlinux-0006: bpf_find_btf_id O(F×M) vs O(F) with hash cache");
{
// 64 loaded kernel modules, BPF map struct with 10 kptr fields
int M = 64, F = 10;
int KIND = 22; // BTF_KIND_STRUCT
// Build module BTFs the target type lives in the last module (worst case)
List<ModuleBtf> moduleBtfs = new ArrayList<>(M);
String[] kptrNames = new String[F];
for (int f = 0; f < F; f++) kptrNames[f] = "kptr_type_" + f;
for (int m = 0; m < M; m++) {
String[] types;
if (m == M - 1) {
// Last module holds all target types
types = Arrays.copyOf(kptrNames, F);
} else {
types = new String[]{"unrelated_type_" + m};
}
moduleBtfs.add(new ModuleBtf("module_" + m, types));
}
// Simulate 500 BPF_MAP_CREATE syscalls each re-scans all kptr fields
int SYSCALLS = 500;
long slowTotal = 0, fastTotal = 0;
for (int s = 0; s < SYSCALLS; s++)
slowTotal += findBtfId_slow(moduleBtfs, kptrNames, KIND);
Map<String, Integer> cache = new HashMap<>();
for (int s = 0; s < SYSCALLS; s++)
fastTotal += findBtfId_fast(moduleBtfs, kptrNames, KIND, cache);
// slow: SYSCALLS × F × avg_M_scanned = 500 × 10 × 64 = 320000
// fast: first call = 500 × 10 × 64 (cold), subsequent = SYSCALLS-1 × F × 1
// 10 × 64 + 499 × 10 = 640 + 4990 = 5630 total for F=10 fields
// (cache warms on first SYSCALL, rest are O(F) hits)
// Actual fast F*M + (SYSCALLS-1)*F = 640+4990 = 5630
// Ratio 320000/5630 56x
bench(String.format("BPF kptr M=%d modules F=%d fields SYSCALLS=%d", M, F, SYSCALLS),
slowTotal, fastTotal, 10L);
total++;
if (slowTotal > fastTotal * 10L) passed++;
}
{
// 200 modules, struct with 25 kptr fields, 1000 map-create events
int M = 200, F = 25, SYSCALLS = 1000;
int KIND = 22;
List<ModuleBtf> moduleBtfs = new ArrayList<>(M);
String[] kptrNames = new String[F];
for (int f = 0; f < F; f++) kptrNames[f] = "heavy_kptr_" + f;
for (int m = 0; m < M; m++) {
String[] types = (m == M - 1)
? Arrays.copyOf(kptrNames, F)
: new String[]{"stub_" + m};
moduleBtfs.add(new ModuleBtf("mod_" + m, types));
}
long slowTotal = 0, fastTotal = 0;
for (int s = 0; s < SYSCALLS; s++)
slowTotal += findBtfId_slow(moduleBtfs, kptrNames, KIND);
Map<String, Integer> cache = new HashMap<>();
for (int s = 0; s < SYSCALLS; s++)
fastTotal += findBtfId_fast(moduleBtfs, kptrNames, KIND, cache);
// slow: 1000 × 25 × 200 = 5,000,000
// fast: first miss = 25×200=5000, then 999×25=24975 30000
// ratio 166x
bench(String.format("BPF kptr M=%d modules F=%d fields SYSCALLS=%d", M, F, SYSCALLS),
slowTotal, fastTotal, 20L);
total++;
if (slowTotal > fastTotal * 20L) passed++;
}
System.out.println("\n" + passed + "/" + total + " PASS");
if (passed < total) System.exit(1);
}
}