diff options
Diffstat (limited to 'ocaml/bench_simple.c')
-rw-r--r-- | ocaml/bench_simple.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/ocaml/bench_simple.c b/ocaml/bench_simple.c new file mode 100644 index 0000000..530746f --- /dev/null +++ b/ocaml/bench_simple.c @@ -0,0 +1,265 @@ +/// Simple standalone Nock benchmark +/// This is a simplified version that doesn't require linking against full Vere + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <time.h> +#include <sys/time.h> +#include <gmp.h> + +// Simplified noun type (direct atom or indirect cell) +typedef uintptr_t noun; + +#define IS_ATOM(n) (!((n) & 1)) +#define IS_CELL(n) ((n) & 1) +#define MAKE_DIRECT_ATOM(n) ((noun)(n) << 1) +#define GET_DIRECT_ATOM(n) ((n) >> 1) + +// Simple cell structure +typedef struct cell_s { + noun head; + noun tail; +} cell_t; + +#define CELL_PTR(n) ((cell_t*)((n) & ~1ULL)) +#define MAKE_CELL(ptr) ((noun)ptr | 1) + +static noun +make_atom(uint64_t val) +{ + return MAKE_DIRECT_ATOM(val); +} + +static noun +make_cell(noun head, noun tail) +{ + cell_t* c = malloc(sizeof(cell_t)); + c->head = head; + c->tail = tail; + return MAKE_CELL(c); +} + +static noun +head(noun n) +{ + return CELL_PTR(n)->head; +} + +static noun +tail(noun n) +{ + return CELL_PTR(n)->tail; +} + +// Simplified slot (no error handling) +static noun +slot(uint64_t axis, noun n) +{ + if (axis == 1) return n; + if (axis & 1) { + // Odd: go right (tail) + return slot(axis >> 1, tail(n)); + } else { + // Even: go left (head) + return slot(axis >> 1, head(n)); + } +} + +// Ultra-simplified nock (only handles the opcodes we benchmark) +static noun +nock_simple(noun subject, noun formula) +{ + if (IS_CELL(formula) && IS_CELL(head(formula))) { + // Cell construction: [[a b] c] -> [nock(a) nock(c)] + noun h = nock_simple(subject, head(formula)); + noun t = nock_simple(subject, tail(formula)); + return make_cell(h, t); + } + + if (!IS_CELL(formula)) return 0; // Error + + noun op = head(formula); + noun arg = tail(formula); + + if (!IS_ATOM(op)) return 0; // Error + + uint64_t opcode = GET_DIRECT_ATOM(op); + + switch (opcode) { + case 0: // slot + if (!IS_ATOM(arg)) return 0; + return slot(GET_DIRECT_ATOM(arg), subject); + + case 1: // constant + return arg; + + case 3: { // is-cell + noun val = nock_simple(subject, arg); + return IS_CELL(val) ? make_atom(0) : make_atom(1); + } + + case 4: { // increment + noun val = nock_simple(subject, arg); + if (!IS_ATOM(val)) return 0; + return MAKE_DIRECT_ATOM(GET_DIRECT_ATOM(val) + 1); + } + + case 5: { // equality + noun pair = nock_simple(subject, arg); + noun a = head(pair); + noun b = tail(pair); + // Simplified: only works for direct atoms + if (IS_ATOM(a) && IS_ATOM(b)) { + return (a == b) ? make_atom(0) : make_atom(1); + } + return make_atom(1); + } + + case 6: { // if-then-else + noun test_fol = head(arg); + noun yes_fol = head(tail(arg)); + noun no_fol = tail(tail(arg)); + + noun test_val = nock_simple(subject, test_fol); + uint64_t test = GET_DIRECT_ATOM(test_val); + + if (test == 0) { + return nock_simple(subject, yes_fol); + } else { + return nock_simple(subject, no_fol); + } + } + + case 7: { // composition + noun b = head(arg); + noun c = tail(arg); + noun new_subj = nock_simple(subject, b); + return nock_simple(new_subj, c); + } + + case 8: { // push + noun b = head(arg); + noun c = tail(arg); + noun val = nock_simple(subject, b); + noun new_subj = make_cell(val, subject); + return nock_simple(new_subj, c); + } + + default: + return 0; // Error + } +} + +static double +get_time_ms(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000.0) + (tv.tv_usec / 1000.0); +} + +static void +bench(const char* name, noun subject, noun formula, int iterations) +{ + double start = get_time_ms(); + + for (int i = 0; i < iterations; i++) { + noun _result = nock_simple(subject, formula); + // Note: we're leaking memory here, but it's fine for a benchmark + } + + double end = get_time_ms(); + double total = end - start; + double per_iter = total / iterations; + + printf("%-30s %8d iterations in %10.2f ms (%10.6f ms/iter, %10.0f ops/sec)\n", + name, iterations, total, per_iter, 1000.0 / per_iter); +} + +int main() +{ + printf("Nock Benchmark - Simple C Implementation\n"); + printf("=========================================\n"); + printf("(Simplified version without full Vere infrastructure)\n\n"); + + int iterations = 1000000; + int slow_iters = 100000; + + // Benchmark 0: slot + bench("Opcode 0: slot/fragment", + make_cell(make_atom(42), make_atom(99)), + make_cell(make_atom(0), make_atom(2)), + iterations); + + // Benchmark 1: constant + bench("Opcode 1: constant", + make_atom(0), + make_cell(make_atom(1), make_atom(42)), + iterations); + + // Benchmark 3: is-cell + bench("Opcode 3: is-cell (atom)", + make_atom(0), + make_cell(make_atom(3), make_cell(make_atom(1), make_atom(42))), + iterations); + + // Benchmark 4: increment + bench("Opcode 4: increment", + make_atom(0), + make_cell(make_atom(4), make_cell(make_atom(1), make_atom(1000))), + iterations); + + // Benchmark 5: equality + bench("Opcode 5: equality (equal)", + make_atom(0), + make_cell(make_atom(5), + make_cell(make_cell(make_atom(1), make_atom(42)), + make_cell(make_atom(1), make_atom(42)))), + iterations); + + // Benchmark 6: if-then-else + bench("Opcode 6: if-then-else", + make_atom(0), + make_cell(make_atom(6), + make_cell(make_cell(make_atom(1), make_atom(0)), + make_cell(make_cell(make_atom(1), make_atom(11)), + make_cell(make_atom(1), make_atom(22))))), + iterations); + + // Benchmark 7: composition + bench("Opcode 7: composition", + make_atom(42), + make_cell(make_atom(7), + make_cell(make_cell(make_atom(1), make_atom(99)), + make_cell(make_atom(0), make_atom(1)))), + iterations); + + // Benchmark 8: push + bench("Opcode 8: push", + make_atom(42), + make_cell(make_atom(8), + make_cell(make_cell(make_atom(1), make_atom(99)), + make_cell(make_atom(0), make_atom(1)))), + iterations); + + // Cell construction + bench("Cell construction", + make_atom(0), + make_cell(make_cell(make_atom(1), make_atom(1)), + make_cell(make_atom(1), make_atom(2))), + iterations); + + // Deep slot lookup + bench("Deep slot lookup (depth 4)", + make_cell(make_cell(make_cell(make_cell(make_atom(1), make_atom(2)), + make_atom(3)), + make_atom(4)), + make_atom(5)), + make_cell(make_atom(0), make_atom(16)), + iterations); + + printf("\n"); + + return 0; +} |