## BaraDB Benchmarks — performance tests for all engines import std/monotimes import std/times import std/random import std/strutils import std/os import std/osproc import std/json import ../src/barabadb/storage/lsm import ../src/barabadb/storage/btree import ../src/barabadb/vector/engine as vengine import ../src/barabadb/vector/simd import ../src/barabadb/fts/engine as fts import ../src/barabadb/graph/engine as gengine # ═══════════════════════════════════════════════════ # Benchmark Result Tracking # ═══════════════════════════════════════════════════ type BenchResult* = object name*: string ops*: int seconds*: float64 opsPerSec*: float64 timestamp*: string BenchReport* = object version*: string gitSha*: string results*: seq[BenchResult] const ResultsFile = "benchmark_results.json" proc loadPreviousResults(path: string): seq[BenchResult] = result = @[] if not fileExists(path): return try: let j = parseFile(path) if j.hasKey("results"): for item in j["results"]: if item.hasKey("name") and item.hasKey("opsPerSec"): result.add(BenchResult( name: item["name"].getStr(), ops: if item.hasKey("ops"): item["ops"].getInt() else: 0, seconds: if item.hasKey("seconds"): item["seconds"].getFloat() else: 0.0, opsPerSec: item["opsPerSec"].getFloat(), timestamp: if item.hasKey("timestamp"): item["timestamp"].getStr() else: "", )) except: discard proc saveResults(path: string, report: BenchReport) = var j = newJObject() j["version"] = %report.version j["gitSha"] = %report.gitSha var arr = newJArray() for r in report.results: var obj = newJObject() obj["name"] = %r.name obj["ops"] = %r.ops obj["seconds"] = %r.seconds obj["opsPerSec"] = %r.opsPerSec obj["timestamp"] = %r.timestamp arr.add(obj) j["results"] = arr writeFile(path, j.pretty()) proc compareResult(name: string, currentOpsPerSec: float64, previous: seq[BenchResult]): string = for p in previous: if p.name == name: let delta = currentOpsPerSec - p.opsPerSec let pct = if p.opsPerSec > 0: (delta / p.opsPerSec) * 100.0 else: 0.0 if abs(pct) < 1.0: return " (≈ same)" elif pct > 0: return " (+" & pct.formatFloat(ffDecimal, 1) & "% vs last)" else: return " (" & pct.formatFloat(ffDecimal, 1) & "% vs last)" return " (new)" var currentResults: seq[BenchResult] = @[] var previousResults = loadPreviousResults(ResultsFile) proc recordResult(name: string, ops: int, seconds: float64) = currentResults.add(BenchResult( name: name, ops: ops, seconds: seconds, opsPerSec: if seconds > 0: float64(ops) / seconds else: 0.0, timestamp: now().format("yyyy-MM-dd HH:mm:ss"), )) proc gitSha(): string = let (output, code) = execCmdEx("git rev-parse --short HEAD") if code == 0: return output.strip() return "unknown" proc elapsed(start: MonoTime): float64 = let ns = float64((getMonoTime() - start).inNanoseconds) return ns / 1_000_000_000.0 proc formatOps(ops: int, secs: float64): string = let rate = float64(ops) / secs if rate > 1_000_000: return $(rate / 1_000_000).formatFloat(ffDecimal, 2) & "M ops/s" elif rate > 1_000: return $(rate / 1_000).formatFloat(ffDecimal, 2) & "K ops/s" else: return $rate.formatFloat(ffDecimal, 2) & " ops/s" proc benchLSMTree() = echo "=== LSM-Tree Storage ===" let benchDir = getTempDir() / "baradb_bench_lsm" removeDir(benchDir) var db = newLSMTree(benchDir) # Write benchmark let n = 100_000 let start = getMonoTime() for i in 0.. 0: inc found let getTime = elapsed(getStart) let getLabel = "BTree-Get" recordResult(getLabel, n, getTime) echo " Get ", n, " keys: ", getTime.formatFloat(ffDecimal, 3), "s (", formatOps(n, getTime), ") (", found, " found)", compareResult(getLabel, currentResults[^1].opsPerSec, previousResults) # Scan benchmark let scanStart = getMonoTime() let scanResults = btree.scan("key_1000", "key_2000") let scanTime = elapsed(scanStart) let scanLabel = "BTree-Scan" recordResult(scanLabel, scanResults.len, scanTime) echo " Scan 1000 range: ", scanTime.formatFloat(ffDecimal, 6), "s (", scanResults.len, " results)", compareResult(scanLabel, currentResults[^1].opsPerSec, previousResults) proc benchVectorSearch() = echo "=== Vector Engine (HNSW) ===" let dim = 128 let n = 10_000 var idx = vengine.newHNSWIndex(dim) # Insert benchmark randomize(42) let start = getMonoTime() for i in 0..