feat: HTTP registry, app/bench harnesses, and DWARF #line maps
Ship QUALITY_PLAN sessions 31–33: fetchable package index URLs, showcase app and micro/nexus benchmarks, and debugger-friendly C codegen. - Registry: BUX_REGISTRY accepts http(s) URLs (curl/wget → ~/.bux/cache) - E.2: make test-apps smoke for nexus/boko/simpledb/jwt-pitbul - E.5: benches/micro + C/Nim/Zig twins; make bench-nexus (wrk) - E.4: HIR locs → #line .bux; default -O0 -g; --release -O2; make test-dwarf
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# Bux benchmarks (E.5)
|
||||
|
||||
Micro-kernels + optional Nexus HTTP throughput for regression and language comparison.
|
||||
|
||||
## Quick run
|
||||
|
||||
```bash
|
||||
# From repo root
|
||||
make bench # Bux micro + C + Nim (+ Zig if installed)
|
||||
make bench-nexus # wrk vs apps/nexus /api/health
|
||||
BENCH_NEXUS=1 make bench
|
||||
```
|
||||
|
||||
## Micro suites
|
||||
|
||||
| Suite | Kernels | Build |
|
||||
|-------|---------|-------|
|
||||
| `micro/` | Bux: `int_loop`, `fib30`, `string_concat`, `array_push` | `buxc build` |
|
||||
| `c/` | C: `fib30`, `int_loop` | `gcc -O2` |
|
||||
| `nim/` | Nim twins | `nim c -d:release --opt:speed` |
|
||||
| `zig/` | Zig twins (optional) | `zig build-exe -OReleaseFast` |
|
||||
|
||||
Output lines:
|
||||
|
||||
```
|
||||
BENCH <name> iters=N total_us=T us_per_op=P
|
||||
```
|
||||
|
||||
## Nexus throughput
|
||||
|
||||
`tools/bench_nexus.sh` / `make bench-nexus`:
|
||||
|
||||
1. Builds `apps/nexus`
|
||||
2. Starts on `NEXUS_PORT` (default **18080**), bind `127.0.0.1`
|
||||
3. `wrk -t4 -c64 -d5s` against `/api/health`
|
||||
4. Prints `BENCH nexus_health rps=…`
|
||||
|
||||
Env knobs:
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
|----------|---------|---------|
|
||||
| `NEXUS_PORT` | `18080` | Listen port (also used by the server binary) |
|
||||
| `NEXUS_WORKERS` | `4` | Worker threads |
|
||||
| `NEXUS_BENCH_DURATION` | `5s` | wrk `-d` |
|
||||
| `NEXUS_BENCH_C` | `64` | wrk connections |
|
||||
| `NEXUS_BENCH_T` | `4` | wrk threads |
|
||||
|
||||
Server-side (any nexus run):
|
||||
|
||||
- `NEXUS_PORT`, `NEXUS_WORKERS`, `NEXUS_BIND`, `NEXUS_PUBLIC`
|
||||
|
||||
## Notes
|
||||
|
||||
- Numbers vary by machine; use them relatively (same host, same day).
|
||||
- Nexus currently closes connections (`Connection: close`) — RPS is honest for that model, not keep-alive maxed.
|
||||
- Requires `wrk` for `bench-nexus` (`apt install wrk` on Debian/Ubuntu).
|
||||
@@ -0,0 +1,26 @@
|
||||
/* C reference: recursive fib(30) — compare with benches/micro fib30 */
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
static int fib(int n) {
|
||||
if (n <= 1) return n;
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
static int64_t now_us(void) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (int64_t)ts.tv_sec * 1000000LL + (int64_t)ts.tv_nsec / 1000LL;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
(void)fib(20); /* warmup */
|
||||
int64_t t0 = now_us();
|
||||
int r = fib(30);
|
||||
int64_t t1 = now_us();
|
||||
if (r < 0) return 1;
|
||||
printf("BENCH fib30 iters=1 total_us=%lld us_per_op=%lld\n",
|
||||
(long long)(t1 - t0), (long long)(t1 - t0));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* C reference: 1e6 integer arithmetic loop */
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
static int64_t now_us(void) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (int64_t)ts.tv_sec * 1000000LL + (int64_t)ts.tv_nsec / 1000LL;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
const int iters = 1000000;
|
||||
int acc = 0;
|
||||
int64_t t0 = now_us();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
acc = acc + i * 3 - 1;
|
||||
}
|
||||
int64_t t1 = now_us();
|
||||
if (acc == 0 && iters > 0) return 1;
|
||||
printf("BENCH int_loop iters=%d total_us=%lld us_per_op=%lld\n",
|
||||
iters, (long long)(t1 - t0), (long long)((t1 - t0) / iters));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[Package]
|
||||
Name = "micro"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
Description = "Micro-benchmarks for Bux (E.5)"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
@@ -0,0 +1,104 @@
|
||||
// Micro-benchmarks (E.5) — recursive fib, string concat, array push.
|
||||
// Prints lines: BENCH name iters total_us us_per_op
|
||||
import Std::Io::{PrintLine, Print};
|
||||
import Std::Time::{Time_NowUs};
|
||||
import Std::String::{String_FromInt, String_Concat, String_Len};
|
||||
import Std::Array::{Array, Array_New, Array_Push, Array_Len, Array_Get};
|
||||
|
||||
func Fib(n: int) -> int {
|
||||
if n <= 1 {
|
||||
return n;
|
||||
}
|
||||
return Fib(n - 1) + Fib(n - 2);
|
||||
}
|
||||
|
||||
func Report(name: String, iters: int, usTotal: int64) {
|
||||
var perOpUs: int64 = 0;
|
||||
if iters > 0 {
|
||||
perOpUs = usTotal / (iters as int64);
|
||||
}
|
||||
Print("BENCH ");
|
||||
Print(name);
|
||||
Print(" iters=");
|
||||
Print(String_FromInt(iters as int64));
|
||||
Print(" total_us=");
|
||||
Print(String_FromInt(usTotal));
|
||||
Print(" us_per_op=");
|
||||
PrintLine(String_FromInt(perOpUs));
|
||||
}
|
||||
|
||||
func BenchIntLoop() {
|
||||
let iters: int = 1000000;
|
||||
var acc: int = 0;
|
||||
var i: int = 0;
|
||||
let t0: int64 = Time_NowUs();
|
||||
while i < iters {
|
||||
acc = acc + i * 3 - 1;
|
||||
i = i + 1;
|
||||
}
|
||||
let t1: int64 = Time_NowUs();
|
||||
if acc == 0 && iters > 0 {
|
||||
PrintLine("unreachable");
|
||||
}
|
||||
Report("int_loop", iters, t1 - t0);
|
||||
}
|
||||
|
||||
func BenchFib() {
|
||||
discard Fib(20);
|
||||
let n: int = 30;
|
||||
let t0: int64 = Time_NowUs();
|
||||
let r: int = Fib(n);
|
||||
let t1: int64 = Time_NowUs();
|
||||
if r < 0 {
|
||||
PrintLine("unreachable");
|
||||
}
|
||||
Report("fib30", 1, t1 - t0);
|
||||
}
|
||||
|
||||
func BenchStringConcat() {
|
||||
let iters: int = 50000;
|
||||
var i: int = 0;
|
||||
let t0: int64 = Time_NowUs();
|
||||
var s: String = "";
|
||||
while i < iters {
|
||||
s = String_Concat(s, "x");
|
||||
if String_Len(s) > 256 {
|
||||
s = "x";
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
let t1: int64 = Time_NowUs();
|
||||
if String_Len(s) < 0 {
|
||||
PrintLine("unreachable");
|
||||
}
|
||||
Report("string_concat", iters, t1 - t0);
|
||||
}
|
||||
|
||||
func BenchArrayPush() {
|
||||
let iters: int = 100000;
|
||||
var arr: Array<int> = Array_New<int>(16);
|
||||
var i: int = 0;
|
||||
let t0: int64 = Time_NowUs();
|
||||
while i < iters {
|
||||
Array_Push<int>(&arr, i);
|
||||
i = i + 1;
|
||||
}
|
||||
let t1: int64 = Time_NowUs();
|
||||
let n: uint = Array_Len<int>(&arr);
|
||||
if n as int != iters {
|
||||
Print("array len mismatch: ");
|
||||
PrintLine(String_FromInt(n as int64));
|
||||
}
|
||||
discard Array_Get<int>(&arr, (iters - 1) as uint);
|
||||
Report("array_push", iters, t1 - t0);
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
PrintLine("=== Bux micro-benchmarks (E.5) ===");
|
||||
BenchIntLoop();
|
||||
BenchFib();
|
||||
BenchStringConcat();
|
||||
BenchArrayPush();
|
||||
PrintLine("=== done ===");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
## Nim twin of benches/c/fib.c — recursive fib(30)
|
||||
import std/[times, strformat]
|
||||
|
||||
proc fib(n: int): int =
|
||||
if n <= 1: return n
|
||||
fib(n - 1) + fib(n - 2)
|
||||
|
||||
proc nowUs(): int64 =
|
||||
int64(epochTime() * 1_000_000.0)
|
||||
|
||||
discard fib(20)
|
||||
let t0 = nowUs()
|
||||
let r = fib(30)
|
||||
let t1 = nowUs()
|
||||
if r < 0: quit(1)
|
||||
echo &"BENCH fib30 iters=1 total_us={t1 - t0} us_per_op={t1 - t0}"
|
||||
@@ -0,0 +1,15 @@
|
||||
## Nim twin of benches/c/int_loop.c — 1e6 integer arithmetic loop
|
||||
import std/[times, strformat]
|
||||
|
||||
proc nowUs(): int64 =
|
||||
int64(epochTime() * 1_000_000.0)
|
||||
|
||||
const iters = 1_000_000
|
||||
var acc = 0
|
||||
let t0 = nowUs()
|
||||
for i in 0 ..< iters:
|
||||
acc = acc + i * 3 - 1
|
||||
let t1 = nowUs()
|
||||
if acc == 0 and iters > 0: quit(1)
|
||||
let total = t1 - t0
|
||||
echo &"BENCH int_loop iters={iters} total_us={total} us_per_op={total div iters}"
|
||||
@@ -0,0 +1,22 @@
|
||||
// Zig twin of benches/c/fib.c — recursive fib(30)
|
||||
// Build: zig build-exe -OReleaseFast -femit-bin=build/fib fib.zig
|
||||
const std = @import("std");
|
||||
|
||||
fn fib(n: i32) i32 {
|
||||
if (n <= 1) return n;
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
fn nowUs() i64 {
|
||||
return @divTrunc(@as(i64, @intCast(std.time.nanoTimestamp())), 1000);
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
_ = fib(20);
|
||||
const t0 = nowUs();
|
||||
const r = fib(30);
|
||||
const t1 = nowUs();
|
||||
if (r < 0) return error.Unreachable;
|
||||
const out = std.io.getStdOut().writer();
|
||||
try out.print("BENCH fib30 iters=1 total_us={d} us_per_op={d}\n", .{ t1 - t0, t1 - t0 });
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Zig twin of benches/c/int_loop.c — 1e6 integer arithmetic loop
|
||||
// Build: zig build-exe -OReleaseFast -femit-bin=build/int_loop int_loop.zig
|
||||
const std = @import("std");
|
||||
|
||||
fn nowUs() i64 {
|
||||
return @divTrunc(@as(i64, @intCast(std.time.nanoTimestamp())), 1000);
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
const iters: i32 = 1_000_000;
|
||||
var acc: i32 = 0;
|
||||
const t0 = nowUs();
|
||||
var i: i32 = 0;
|
||||
while (i < iters) : (i += 1) {
|
||||
acc = acc + i * 3 - 1;
|
||||
}
|
||||
const t1 = nowUs();
|
||||
if (acc == 0 and iters > 0) return error.Unreachable;
|
||||
const total = t1 - t0;
|
||||
const out = std.io.getStdOut().writer();
|
||||
try out.print("BENCH int_loop iters={d} total_us={d} us_per_op={d}\n", .{ iters, total, @divTrunc(total, iters) });
|
||||
}
|
||||
Reference in New Issue
Block a user