Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
241 lines
14 KiB
Java
241 lines
14 KiB
Java
package bench;
|
||
|
||
import support.MongodbIndexPlannerAlgorithm;
|
||
import support.MongodbIndexPlannerAlgorithm.DefectiveRelevantTag;
|
||
import support.MongodbIndexPlannerAlgorithm.FixedRelevantTag;
|
||
import support.MongodbIndexPlannerAlgorithm.StripResult;
|
||
import support.MongodbIndexPlannerAlgorithm.EnumResult;
|
||
import support.MongodbPipelineAlgorithm;
|
||
import support.MongodbPipelineAlgorithm.FieldIndexResult;
|
||
import support.MongodbPipelineAlgorithm.OptimizationResult;
|
||
|
||
import java.util.*;
|
||
|
||
/**
|
||
* MongodbBenchmark — timing benchmark for mongodb-0001 through -0004.
|
||
*
|
||
* Four sites across two MongoDB subsystems, all CWE-407:
|
||
*
|
||
* mongodb-0001 planner_ixselect.cpp (4 sites) RelevantTag vector<size_t> CRITICAL
|
||
* mongodb-0002 plan_enumerator.cpp (4 sites) predicate vector tracking HIGH
|
||
* mongodb-0003 unpack_bucket.cpp stage vector tracking HIGH
|
||
* mongodb-0004 streaming_group.cpp idFieldNames vector scan MEDIUM
|
||
*
|
||
* Root cause of 0001: single struct change in index_tag.h:106-107
|
||
* std::vector<size_t> first; → std::unordered_set<size_t> first;
|
||
* std::vector<size_t> notFirst; → std::unordered_set<size_t> notFirst;
|
||
* fixes all 4 planner_ixselect.cpp sites simultaneously.
|
||
*
|
||
* These are ALGORITHM MICRO-BENCHMARKS, not real MongoDB query timings.
|
||
* Real query planning also involves BSON parsing, candidate index selection,
|
||
* and other work. The micro-benchmark isolates the membership-check cost.
|
||
*/
|
||
public class MongodbBenchmark {
|
||
|
||
static final int WARMUP_ROUNDS = 5;
|
||
|
||
// ── 0001: planner_ixselect.cpp — RelevantTag strip passes ────────────────
|
||
|
||
static void bench0001() {
|
||
System.out.println();
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.println(" mongodb-0001 — planner_ixselect.cpp RelevantTag (4 sites, CRITICAL)");
|
||
System.out.println(" Root cause: index_tag.h:106-107 vector<size_t> → unordered_set<size_t>");
|
||
System.out.println(" Defect: std::find O(M) per node Fix: .count() O(1) per node");
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.printf(" %-10s %-10s %-14s %-12s %s%n",
|
||
"N nodes", "M indexes", "Defective (ms)", "Fixed (ms)", "Speedup");
|
||
System.out.println(" " + "─".repeat(60));
|
||
|
||
int idxPerTag = 20;
|
||
int totalIdxs = 30;
|
||
|
||
for (int n : new int[]{50, 200, 500, 1000, 2000, 5000}) {
|
||
Random rng1 = new Random(42);
|
||
Random rng2 = new Random(42);
|
||
|
||
List<DefectiveRelevantTag> defTags =
|
||
MongodbIndexPlannerAlgorithm.buildDefectiveTags(n, idxPerTag, totalIdxs, rng1);
|
||
List<FixedRelevantTag> fixTags =
|
||
MongodbIndexPlannerAlgorithm.buildFixedTags(n, idxPerTag, totalIdxs, rng2);
|
||
|
||
// warmup
|
||
for (int i = 0; i < WARMUP_ROUNDS; i++) {
|
||
MongodbIndexPlannerAlgorithm.defectiveStripInvalidAssignments(defTags, 5);
|
||
MongodbIndexPlannerAlgorithm.fixedStripInvalidAssignments(fixTags, 5);
|
||
}
|
||
|
||
long t0 = System.nanoTime();
|
||
StripResult def = MongodbIndexPlannerAlgorithm.defectiveStripInvalidAssignments(defTags, 5);
|
||
long defNs = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
StripResult fix = MongodbIndexPlannerAlgorithm.fixedStripInvalidAssignments(fixTags, 5);
|
||
long fixNs = System.nanoTime() - t0;
|
||
|
||
System.out.printf(" %-10d %-10d %-14.3f %-12.3f %.1fx%n",
|
||
n, idxPerTag,
|
||
defNs / 1e6,
|
||
fixNs / 1e6,
|
||
(double) defNs / Math.max(1, fixNs));
|
||
}
|
||
}
|
||
|
||
// ── 0002: plan_enumerator.cpp — predicate de-dup ─────────────────────────
|
||
|
||
static void bench0002() {
|
||
System.out.println();
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.println(" mongodb-0002 — plan_enumerator.cpp predicate tracking (4 sites, HIGH)");
|
||
System.out.println(" Defect: std::vector<MatchExpression*> std::find O(A) per predicate");
|
||
System.out.println(" Fix: std::unordered_set<MatchExpression*> O(1) per predicate");
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.printf(" %-12s %-14s %-12s %s%n",
|
||
"P predicates", "Defective (ms)", "Fixed (ms)", "Speedup");
|
||
System.out.println(" " + "─".repeat(50));
|
||
|
||
Random predRng = new Random(42);
|
||
|
||
for (int p : new int[]{20, 50, 100, 200, 500, 1000}) {
|
||
List<Integer> preds = new ArrayList<>();
|
||
for (int i = 0; i < p; i++) preds.add(i);
|
||
for (int i = 0; i < p / 4; i++) preds.add(predRng.nextInt(p));
|
||
Collections.shuffle(preds, predRng);
|
||
|
||
// warmup
|
||
for (int i = 0; i < WARMUP_ROUNDS; i++) {
|
||
MongodbIndexPlannerAlgorithm.defectiveEnumeratePreds(preds);
|
||
MongodbIndexPlannerAlgorithm.fixedEnumeratePreds(preds);
|
||
}
|
||
|
||
long t0 = System.nanoTime();
|
||
EnumResult def = MongodbIndexPlannerAlgorithm.defectiveEnumeratePreds(preds);
|
||
long defNs = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
EnumResult fix = MongodbIndexPlannerAlgorithm.fixedEnumeratePreds(preds);
|
||
long fixNs = System.nanoTime() - t0;
|
||
|
||
System.out.printf(" %-12d %-14.3f %-12.3f %.1fx%n",
|
||
preds.size(),
|
||
defNs / 1e6,
|
||
fixNs / 1e6,
|
||
(double) defNs / Math.max(1, fixNs));
|
||
}
|
||
}
|
||
|
||
// ── 0003: document_source_internal_unpack_bucket.cpp ─────────────────────
|
||
|
||
static void bench0003() {
|
||
System.out.println();
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.println(" mongodb-0003 — unpack_bucket.cpp stage tracking (HIGH)");
|
||
System.out.println(" Defect: std::vector<DocumentSource*> _triedComputedMetaPushDownFor");
|
||
System.out.println(" Fix: std::unordered_set<DocumentSource*> O(1) lookup");
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.printf(" %-10s %-14s %-12s %s%n",
|
||
"S stages", "Defective (ms)", "Fixed (ms)", "Speedup");
|
||
System.out.println(" " + "─".repeat(50));
|
||
|
||
Random rng = new Random(42);
|
||
|
||
for (int s : new int[]{20, 50, 100, 200, 500, 1000}) {
|
||
List<Integer> stages = new ArrayList<>();
|
||
for (int i = 0; i < s; i++) stages.add(i);
|
||
for (int i = 0; i < s / 4; i++) stages.add(rng.nextInt(s));
|
||
Collections.shuffle(stages, rng);
|
||
|
||
// warmup
|
||
for (int i = 0; i < WARMUP_ROUNDS; i++) {
|
||
MongodbPipelineAlgorithm.defectiveTrackStages(stages);
|
||
MongodbPipelineAlgorithm.fixedTrackStages(stages);
|
||
}
|
||
|
||
long t0 = System.nanoTime();
|
||
OptimizationResult def = MongodbPipelineAlgorithm.defectiveTrackStages(stages);
|
||
long defNs = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
OptimizationResult fix = MongodbPipelineAlgorithm.fixedTrackStages(stages);
|
||
long fixNs = System.nanoTime() - t0;
|
||
|
||
System.out.printf(" %-10d %-14.3f %-12.3f %.1fx%n",
|
||
stages.size(),
|
||
defNs / 1e6,
|
||
fixNs / 1e6,
|
||
(double) defNs / Math.max(1, fixNs));
|
||
}
|
||
}
|
||
|
||
// ── 0004: document_source_streaming_group.cpp ────────────────────────────
|
||
|
||
static void bench0004() {
|
||
System.out.println();
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.println(" mongodb-0004 — streaming_group.cpp field index resolution (MEDIUM)");
|
||
System.out.println(" Defect: std::find on idFieldNames O(N × M)");
|
||
System.out.println(" Fix: unordered_map<field→index> built once O(N + M)");
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.printf(" %-8s %-8s %-14s %-12s %s%n",
|
||
"N fields", "M mono", "Defective (ms)", "Fixed (ms)", "Speedup");
|
||
System.out.println(" " + "─".repeat(56));
|
||
|
||
for (int n : new int[]{10, 20, 50, 100, 200, 500}) {
|
||
List<String> idFields = new ArrayList<>();
|
||
for (int i = 0; i < n; i++) idFields.add("field_" + i);
|
||
List<String> mono = new ArrayList<>(idFields.subList(n / 2, n));
|
||
|
||
// warmup
|
||
for (int i = 0; i < WARMUP_ROUNDS; i++) {
|
||
MongodbPipelineAlgorithm.defectiveResolveIndexes(idFields, mono);
|
||
MongodbPipelineAlgorithm.fixedResolveIndexes(idFields, mono);
|
||
}
|
||
|
||
long t0 = System.nanoTime();
|
||
FieldIndexResult def = MongodbPipelineAlgorithm.defectiveResolveIndexes(idFields, mono);
|
||
long defNs = System.nanoTime() - t0;
|
||
|
||
t0 = System.nanoTime();
|
||
FieldIndexResult fix = MongodbPipelineAlgorithm.fixedResolveIndexes(idFields, mono);
|
||
long fixNs = System.nanoTime() - t0;
|
||
|
||
System.out.printf(" %-8d %-8d %-14.3f %-12.3f %.1fx%n",
|
||
n, mono.size(),
|
||
defNs / 1e6,
|
||
fixNs / 1e6,
|
||
(double) defNs / Math.max(1, fixNs));
|
||
}
|
||
}
|
||
|
||
// ── Main ─────────────────────────────────────────────────────────────────
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println();
|
||
System.out.println("╔══════════════════════════════════════════════════════════════════╗");
|
||
System.out.println("║ MongodbBenchmark — CWE-407 algorithm micro-benchmarks ║");
|
||
System.out.println("║ mongodb-0001 mongodb-0002 mongodb-0003 mongodb-0004 ║");
|
||
System.out.println("╠══════════════════════════════════════════════════════════════════╣");
|
||
System.out.println("║ All sites: list membership O(n²/n×m) → hash set O(n) ║");
|
||
System.out.println("║ mongodb-0001 root cause: single struct change in index_tag.h ║");
|
||
System.out.println("║ NOTE: algorithm isolation — not real MongoDB query timings ║");
|
||
System.out.println("╚══════════════════════════════════════════════════════════════════╝");
|
||
|
||
bench0001();
|
||
bench0002();
|
||
bench0003();
|
||
bench0004();
|
||
|
||
System.out.println();
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.println(" SUMMARY");
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
System.out.println(" mongodb-0001 PATCHED index_tag.h:106-107 + planner_ixselect.cpp (4 sites)");
|
||
System.out.println(" mongodb-0002 PATCHED plan_enumerator.cpp (4 sites)");
|
||
System.out.println(" mongodb-0003 PATCHED unpack_bucket.h:457 + unpack_bucket.cpp:1076");
|
||
System.out.println(" mongodb-0004 PATCHED streaming_group.cpp:142");
|
||
System.out.println(" mongodb-0005 DEFERRED ce_cache.h:122 — IndexBounds, no hash");
|
||
System.out.println(" mongodb-0006 NOT-WORTH-FIXING projection_ast.h:262 — removeChild O(n) erase irreducible");
|
||
System.out.println(" mongodb-0007 NOT-WORTH-FIXING join_graph.cpp — InlinedVector<2>, A≈1 at runtime");
|
||
System.out.println("══════════════════════════════════════════════════════════════════");
|
||
}
|
||
}
|