diff options
| author | 2025-08-19 15:52:38 +0330 | |
|---|---|---|
| committer | 2025-08-19 15:52:38 +0330 | |
| commit | 0bd4c2925a32d384ea2c333b950115404b88c619 (patch) | |
| tree | e5c447a5425869626473394010cc470b11b51451 | |
| parent | improved pu2 (vm speed ~1GHz on 1.8GHz cpu), reduced code emission, added ano... (diff) | |
the speedster
| -rw-r--r-- | pu2/pu2.c | 16 | ||||
| -rw-r--r-- | pu2/pu2.out.c | 137 |
2 files changed, 99 insertions, 54 deletions
@@ -281,8 +281,13 @@ clean_slice_ref(slice *val) { free(val->ref); } char T; string ERR; string ERR_code; -int *Code = &m[ 4000 ]; -int *Data = &m[ static_len(m) - 1 ]; // grows downwards +int *Code; +int *Data; + +init_ir2() { + Code = &m[ 4000 ]; + Data = &m[ S * sizeof(int) - 1 ]; // grows downwards +} __attribute__((always_inline)) emit(int op, int val) { *Code++ = op; @@ -650,7 +655,7 @@ double bench_cycle(int instr) { int i; for (i = 0; i < S - 2; i += 2) { m[ i ] = instr; - m[ i + 1 ] = 5; + m[ i + 1 ] = 10; } m[ S - 2 ] = 0; m[ S - 1 ] = 0; @@ -785,6 +790,9 @@ main(int argc, char **argv) { argv[ 0 ]); } + init_pu2(); + init_ir2(); + if (strcmp(argv[ 1 ], "benchmark") == 0) { benchmark(bench_cycle, "time"); @@ -800,7 +808,7 @@ main(int argc, char **argv) { unsigned long long t1 = rdtsc(); out = sum; // single volatile write to make sum observable printf( - "N=%llu cycles=%llu cycles/iter=%.6f\n", + "(absolute max) N=%llu cycles=%llu cycles/iter=%.6f\n", (unsigned long long) N, (unsigned long long) (t1 - t0), (t1 - t0) / (double) N); diff --git a/pu2/pu2.out.c b/pu2/pu2.out.c index d168321..3f165de 100644 --- a/pu2/pu2.out.c +++ b/pu2/pu2.out.c @@ -1,6 +1,7 @@ #include <ctype.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #pragma clang diagnostic ignored "-Wparentheses" #pragma clang diagnostic ignored "-Wreturn-type" #pragma clang diagnostic ignored "-Wempty-body" @@ -19,7 +20,7 @@ #define __PU2_SPEED_IMPROVEMENT #define __PU2_EXTENDED_INSTRUCTION_SET -#define S (1 << 25) +#define S (1 << 26) #define J while #define H !--c @@ -62,105 +63,141 @@ // not implemented yet, was lazy // bake(int start, int end) {} -__attribute__((aligned(64))) m[ S ], a, b, u, c; + #define unlikely(JJ) __builtin_expect((JJ), 0) + #define likely(JJ) __builtin_expect((JJ), 1) + +__attribute__((aligned(64))) * m, a, b, u, c; typedef struct { int c; int v; } vminst; -pu2() { - vminst *M = (vminst *) m; - int s1, s2, s3; +const int hugepage_size = 2 * 1024 * 1024; + +init_pu2() { + const int S_val = S * sizeof(int); + const int page_count = (S_val / hugepage_size) + 1; + const int page_size = page_count * hugepage_size; + m = mmap( + NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); + if (m == MAP_FAILED) { + perror("[warn] couldn't allocate pu2 memory"); + printf( + " ( hint: enable hugepages in your kernel settings\n `echo %i | " + "sudo " + "tee /proc/sys/vm/nr_hugepages` )", + page_count); + exit(1); + } + + size_t i; + for (i = 0; i < 64; i++) ((char *) m)[ i * hugepage_size ] = 0; +} + + #define asm(...) __asm__(__VA_ARGS__) + +__attribute__((hot, aligned(64))) pu2() { + vminst *M2 = (vminst *) m; + vminst *M = &M2[ m[ 7 ] >> 1 ]; - const __attribute__((aligned(64))) void *PRECOMPUTED_TABLE[] - = { &&C_ZERO, &&C_ONE, &&C_TWO, &&C_THREE, &&C_FOUR, - &&C_FIVE, &&C_SIX, &&C_SEVEN, &&C_EIGHT, &&C_NINE, - &&C_TEN, &&C_ELEVEN, &&C_TWELVE, &&C_THIRTEEN, &&CB_FOURTEEN, - &&CB_FIFTEEN, &&CB_SIXTEEN, &&CB_SEVENTEEN, &&CB_EIGHTEEN }; - int pc = m[ 7 ] >> 1; - register vminst inst; - J(inst = M[ pc++ ], inst.c) { - if (__builtin_expect(inst.c > 18, 0)) A; + static int s1, s2, s3; + static const __attribute__((aligned(64))) void *PRECOMPUTED_TABLE[] + = { &&C_ZERO, &&C_ONE, &&C_TWO, &&C_THREE, &&C_FOUR, + &&C_FIVE, &&C_SIX, &&C_SEVEN, &&C_EIGHT, &&C_NINE, + &&C_TEN, &&C_ELEVEN, &&C_TWELVE, &&C_THIRTEEN, &&CB_FOURTEEN, + &&CB_FIFTEEN, &&CB_SIXTEEN, &&CB_SEVENTEEN, &&CB_EIGHTEEN, [32] = 0 }; + static vminst inst __asm__("r21"); + + while (1) { + PU2_START: + inst = *M++; + // if (unlikely(inst.c > 18)) A; + __builtin_prefetch(M + 1, 0, 3); goto *PRECOMPUTED_TABLE[ inst.c ]; C_ZERO: - break; + goto PU2_END; C_ONE: - a = inst.v; - continue; + asm("mov %1, %0" : "=r"(a) : "r"(inst.v)); + goto PU2_START; C_TWO: - a = m[ b ]; - continue; + asm("mov %1, %0" : "=r"(a) : "r"(m[b])); + goto PU2_START; C_THREE: - if (u) { - if (__builtin_expect(a == 7, 0)) pc = b >> 1; + if (likely(u)) { + if (unlikely(a == 7)) M = M2 + (b >> 1); m[ a ] = b; } - continue; + goto PU2_START; C_FOUR: - s1 = a; - a = b; - b = s1; - - continue; + asm("xchg %0, %1" : "+r"(a), "+r"(b)); + goto PU2_START; C_FIVE: a += b; - continue; + goto PU2_START; C_SIX: a -= b; - continue; + goto PU2_START; C_SEVEN: - a = !a; - continue; + a &= b; + goto PU2_START; C_EIGHT: - u = inst.v; - continue; + a = !a; + goto PU2_START; C_NINE: u = inst.v; - continue; + goto PU2_START; C_TEN: u = a; - continue; + goto PU2_START; C_ELEVEN: a = u; - continue; + goto PU2_START; C_TWELVE: u = b; - continue; + goto PU2_START; C_THIRTEEN: b = u; - continue; - CB_FOURTEEN: // nop + goto PU2_START; + CB_FOURTEEN: + // nop // this instruction allows for essentially embedding data inside a program, as pu2 will skip // right over it - pc += inst.v; - continue; + M += inst.v; + goto PU2_START; CB_FIFTEEN: - if (__builtin_expect(inst.v == 7, 0)) pc = m[ a ] >> 1; + // if (unlikely(inst.v == 7)) pc = m[ a ] >> 1; + if (unlikely(inst.v == a)) goto PU2_START; m[ inst.v ] = m[ a ]; - continue; + // asm("mov %1, %0" : "=r"(m[inst.v]) : "r"(m[a])); + goto PU2_START; CB_SIXTEEN: + // asm("mov %1, %0" : "=r"(a) : "r"(m[inst.v])); a = m[ inst.v ]; - continue; + goto PU2_START; CB_SEVENTEEN: - if (__builtin_expect(a == 7, 0)) pc = inst.v >> 1; + // if (unlikely(a == 7)) pc = inst.v >> 1; + // asm("mov %1, %0" : "=r"(m[a]) : "r"(inst.v)); m[ a ] = inst.v; - continue; + goto PU2_START; CB_EIGHTEEN: - if (__builtin_expect(a == 7, 0)) pc = m[ inst.v ] >> 1; + // if (unlikely(a == 7)) pc = m[ inst.v ] >> 1; + if (unlikely(inst.v == a)) goto PU2_START; m[ a ] = m[ inst.v ]; - continue; + // asm("mov %1, %0" : "=r"(m[a]) : "r"(m[inst.v])); + goto PU2_START; } - m[ 7 ] = pc << 1; +PU2_END: + m[ 7 ] = (M - M2) << 1; } #endif // there's just memory. no, really -// ok actually there's c_one registers called a and b +// ok actually there's two registers called a and b // 0 HLT: halt // 1 IMM: a = imm // 2 LOD: a = m[b] |
