diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4fd482..b8c2e90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -107,8 +107,8 @@ jobs: make "${{ matrix.target }}" \ TLS_CFLAGS="-I$GITHUB_WORKSPACE/openssl-static/include" \ TLS_LDLIBS="$OPENSSL_LIBDIR/libssl.a $OPENSSL_LIBDIR/libcrypto.a $EXTRA_STATIC_LIBS" - file "dist/fossmark-${{ matrix.target }}" - if ldd "dist/fossmark-${{ matrix.target }}" | grep -E 'lib(ssl|crypto)'; then + file "dist/fossbench-${{ matrix.target }}" + if ldd "dist/fossbench-${{ matrix.target }}" | grep -E 'lib(ssl|crypto)'; then echo 'Linux release uses dynamic OpenSSL' >&2 exit 1 fi @@ -122,19 +122,19 @@ jobs: make "${{ matrix.target }}" \ TLS_CFLAGS="-I$GITHUB_WORKSPACE/openssl-static/include" \ TLS_LDLIBS="$OPENSSL_LIBDIR/libssl.a $OPENSSL_LIBDIR/libcrypto.a" - if otool -L "dist/fossmark-${{ matrix.target }}" | grep -E 'lib(ssl|crypto)'; then + if otool -L "dist/fossbench-${{ matrix.target }}" | grep -E 'lib(ssl|crypto)'; then echo 'macOS release uses dynamic OpenSSL' >&2 exit 1 fi - name: Package artifact - run: tar -czf fossmark-${{ matrix.target }}.tar.gz -C dist fossmark-${{ matrix.target }} + run: tar -czf fossbench-${{ matrix.target }}.tar.gz -C dist fossbench-${{ matrix.target }} - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: fossmark-${{ matrix.target }} - path: fossmark-${{ matrix.target }}.tar.gz + name: fossbench-${{ matrix.target }} + path: fossbench-${{ matrix.target }}.tar.gz if-no-files-found: error release: @@ -149,13 +149,13 @@ jobs: - name: Download build artifacts uses: actions/download-artifact@v4 with: - pattern: fossmark-* + pattern: fossbench-* path: release merge-multiple: true - name: Create checksums working-directory: release - run: sha256sum fossmark-*.tar.gz > SHA256SUMS + run: sha256sum fossbench-*.tar.gz > SHA256SUMS - name: Create release and attach artifacts env: @@ -166,7 +166,7 @@ jobs: --repo "$GITHUB_REPOSITORY" \ --yes 2>/dev/null || true gh release create "$RELEASE_TAG" \ - release/fossmark-*.tar.gz \ + release/fossbench-*.tar.gz \ release/SHA256SUMS \ --repo "$GITHUB_REPOSITORY" \ --title "Release $RELEASE_TAG" \ diff --git a/Makefile b/Makefile index 9f92b49..6c70e6f 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,18 @@ -# fossmark - multi-core CPU benchmark +# fossbench - multi-core CPU benchmark # # The assembly kernels are architecture-specific: -# src/fossmark.S AArch64 (ARM64) -# src/fossmark_x86_64.S x86-64 (AMD64) -# src/fossmark_i386.S x86 32-bit (i386, Pentium 4 baseline) -# src/fossmark_ppc32.c PowerPC 32-bit, including big-endian systems +# src/fossbench.S AArch64 (ARM64) +# src/fossbench_x86_64.S x86-64 (AMD64) +# src/fossbench_i386.S x86 32-bit (i386, Pentium 4 baseline) +# src/fossbench_ppc32.c PowerPC 32-bit, including big-endian systems # and the portable PPC64 kernel implementations # The C driver (src/main.c) is portable across architectures and OSes. A # "binary that runs everywhere" is not possible - each OS/arch pair uses a # different executable format and instruction set - so output is named per -# platform, e.g. dist/fossmark-linux-arm64, dist/fossmark-linux-amd64. +# platform, e.g. dist/fossbench-linux-arm64, dist/fossbench-linux-amd64. # # Common targets: -# make build for the host arch (dist/fossmark--) +# make build for the host arch (dist/fossbench--) # make linux-arm64 build the Linux/ARM64 binary # make linux-amd64 build the Linux/AMD64 binary # make linux-ppc64be build Linux/PPC64 big-endian for an iMac G5 @@ -47,12 +47,12 @@ PTHREAD := -pthread DIST := dist DRIVER := src/main.c -ASM_ARM64 := src/fossmark.S -ASM_AMD64 := src/fossmark_x86_64.S -ASM_I386 := src/fossmark_i386.S -SRC_PPC32 := src/fossmark_ppc32.c -ASM_PPC32 := src/fossmark_ppc32_ext.S -SRC_PPC64 := src/fossmark_ppc32.c +ASM_ARM64 := src/fossbench.S +ASM_AMD64 := src/fossbench_x86_64.S +ASM_I386 := src/fossbench_i386.S +SRC_PPC32 := src/fossbench_ppc32.c +ASM_PPC32 := src/fossbench_ppc32_ext.S +SRC_PPC64 := src/fossbench_ppc32.c # ---- host detection: normalise `uname -m` to our arch names ---- HOST_ARCH := $(shell uname -m) @@ -76,7 +76,7 @@ else $(error unsupported host architecture '$(HOST_ARCH)') endif ifeq ($(HOST_ARCHNAME),i386) - # The kernels are hand-written assembly (fossmark_i386.S) using SSE2 + # The kernels are hand-written assembly (fossbench_i386.S) using SSE2 # directly, so -msse2/-mfpmath=sse have nothing left to gate - only # main.c (the portable driver) is still compiled from C here. # @@ -136,7 +136,7 @@ else CC_PPC64BE ?= powerpc64-linux-gnu-gcc endif -NATIVE_BIN := $(DIST)/fossmark-$(OSNAME)-$(HOST_ARCHNAME) +NATIVE_BIN := $(DIST)/fossbench-$(OSNAME)-$(HOST_ARCHNAME) # `make` with no target builds the host binary, as before. .DEFAULT_GOAL := native @@ -148,39 +148,39 @@ all: linux-arm64 linux-amd64 linux-i386 linux-ppc32be linux-ppc64be # `make native` (and bare `make`) build for whatever host you are on. native: $(NATIVE_BIN) -linux-arm64: $(DIST)/fossmark-linux-arm64 -linux-amd64: $(DIST)/fossmark-linux-amd64 -linux-i386: $(DIST)/fossmark-linux-i386 -linux-ppc32be: $(DIST)/fossmark-linux-ppc32be -linux-ppc64be: $(DIST)/fossmark-linux-ppc64be -macos-arm64: $(DIST)/fossmark-macos-arm64 -macos-amd64: $(DIST)/fossmark-macos-amd64 +linux-arm64: $(DIST)/fossbench-linux-arm64 +linux-amd64: $(DIST)/fossbench-linux-amd64 +linux-i386: $(DIST)/fossbench-linux-i386 +linux-ppc32be: $(DIST)/fossbench-linux-ppc32be +linux-ppc64be: $(DIST)/fossbench-linux-ppc64be +macos-arm64: $(DIST)/fossbench-macos-arm64 +macos-amd64: $(DIST)/fossbench-macos-amd64 -$(DIST)/fossmark-linux-arm64: $(DRIVER) $(ASM_ARM64) | $(DIST) +$(DIST)/fossbench-linux-arm64: $(DRIVER) $(ASM_ARM64) | $(DIST) $(CC_ARM64) $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_ARM64) $(LDLIBS) @echo "built $@" -$(DIST)/fossmark-linux-amd64: $(DRIVER) $(ASM_AMD64) | $(DIST) +$(DIST)/fossbench-linux-amd64: $(DRIVER) $(ASM_AMD64) | $(DIST) $(CC_AMD64) $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_AMD64) $(LDLIBS) @echo "built $@" -$(DIST)/fossmark-linux-i386: $(DRIVER) $(ASM_I386) | $(DIST) +$(DIST)/fossbench-linux-i386: $(DRIVER) $(ASM_I386) | $(DIST) $(CC_I386) -m32 -march=pentium4 -fno-pie -no-pie $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_I386) $(LDLIBS) @echo "built $@" -$(DIST)/fossmark-linux-ppc32be: $(DRIVER) $(SRC_PPC32) $(ASM_PPC32) | $(DIST) +$(DIST)/fossbench-linux-ppc32be: $(DRIVER) $(SRC_PPC32) $(ASM_PPC32) | $(DIST) $(CC_PPC32BE) $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(SRC_PPC32) $(ASM_PPC32) $(LDLIBS) @echo "built $@" -$(DIST)/fossmark-linux-ppc64be: $(DRIVER) $(SRC_PPC64) | $(DIST) +$(DIST)/fossbench-linux-ppc64be: $(DRIVER) $(SRC_PPC64) | $(DIST) $(CC_PPC64BE) -mcpu=970 -maltivec $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(SRC_PPC64) $(LDLIBS) @echo "built $@" -$(DIST)/fossmark-macos-arm64: $(DRIVER) $(ASM_ARM64) | $(DIST) +$(DIST)/fossbench-macos-arm64: $(DRIVER) $(ASM_ARM64) | $(DIST) $(CC_MACOS_ARM64) -arch arm64 $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_ARM64) $(LDLIBS) @echo "built $@" -$(DIST)/fossmark-macos-amd64: $(DRIVER) $(ASM_AMD64) | $(DIST) +$(DIST)/fossbench-macos-amd64: $(DRIVER) $(ASM_AMD64) | $(DIST) MACOSX_DEPLOYMENT_TARGET=$(MACOS_AMD64_MIN) $(CC_MACOS_AMD64) -arch x86_64 -mmacosx-version-min=$(MACOS_AMD64_MIN) $(CFLAGS) $(TLS_CFLAGS) $(PTHREAD) $(LDFLAGS) -Wl,-no_fixup_chains -o $@ $(DRIVER) $(ASM_AMD64) $(LDLIBS) @echo "built $@" diff --git a/README.md b/README.md index 6d6d271..a7b81ba 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ small C driver. It measures each workload twice: once on a single core and once across every available core. The final report includes separate single-core and multicore scores. -The repository currently builds an executable named `fossmark` for ARM64, +The repository currently builds an executable named `fossbench` for ARM64, x86 (Pentium 4 or newer), x86-64, and 32- or 64-bit big-endian PowerPC. The C driver handles timing, memory, threads, output, and scoring. Performance-sensitive kernels live in architecture-specific backend files. @@ -43,7 +43,7 @@ make bench ``` `make` builds a binary for the host at -`dist/fossmark--`. `make bench` builds that binary and runs it. +`dist/fossbench--`. `make bench` builds that binary and runs it. Other targets are available for explicit platforms and architectures: @@ -81,23 +81,35 @@ deployment floor when needed with `MACOS_AMD64_MIN`, for example Run the benchmark with extra per-test details by passing `--verbose`: ```sh -./dist/fossmark-linux-amd64 --verbose +./dist/fossbench-linux-amd64 --verbose ``` The exact filename depends on the host platform and architecture. -At startup, fossmark reports the detected CPU model, physical cores, logical +At startup, fossbench reports the detected CPU model, physical cores, logical threads, installed memory, operating system, architecture, and compiler. At the end it prints the composite scores and total benchmark duration, then asks -whether to upload the result. Uploading is anonymous and opt-in; no account or -API token is required. +whether to upload the result. Uploading is opt-in and anonymous by default; no +account or API token is required. Pass `--upload` to upload without asking, or +`--noupload` to skip the prompt and never upload. -The API base URL is defined by `FM_API_BASE_URL` in `src/main.c` and defaults to +To associate results with your fossbench.net profile instead of submitting +anonymously, create an API token under Account -> Benchmark client API token +and set it in the environment: + +```sh +export FOSSBENCH_TOKEN=fb_your_token_here +./dist/fossbench-linux-amd64 --upload +``` + +The token is never printed or logged by fossbench. + +The API base URL is defined by `FB_API_BASE_URL` in `src/main.c` and defaults to `https://fossbench.net`. A release build can override it without editing the source: ```sh -make CFLAGS='-O2 -Wall -Wextra -DFM_API_BASE_URL=\"https://bench.example.com\"' +make CFLAGS='-O2 -Wall -Wextra -DFB_API_BASE_URL=\"https://bench.example.com\"' ``` HTTPS uploads use OpenSSL with certificate and hostname verification. @@ -162,14 +174,14 @@ normal. The kernel backends use only baseline instructions for their architecture: -* `src/fossmark.S` uses ARMv8-A and NEON under AAPCS64. -* `src/fossmark_x86_64.S` uses baseline x86-64 and SSE2 under the System V ABI. -* `src/fossmark_i386.S` uses baseline 32-bit x86 (Pentium 4) and SSE2 under the +* `src/fossbench.S` uses ARMv8-A and NEON under AAPCS64. +* `src/fossbench_x86_64.S` uses baseline x86-64 and SSE2 under the System V ABI. +* `src/fossbench_i386.S` uses baseline 32-bit x86 (Pentium 4) and SSE2 under the i386 System V (cdecl) ABI. With only six general-purpose registers, no 64-bit integer registers, and half of amd64's SSE2 register file (xmm0-7), several kernels keep working state on the stack instead of in registers - a real cost of the architecture, not an oversight. -* `src/fossmark_ppc32.c` is endian-safe and keeps a baseline 32-bit PowerPC +* `src/fossbench_ppc32.c` is endian-safe and keeps a baseline 32-bit PowerPC fallback. At runtime, the extended-instruction test uses Paired Singles when the device-tree `compatible` property begins with `nintendo,`; otherwise it selects VSX, AltiVec, or the scalar fallback in that order according to @@ -208,11 +220,11 @@ with a nonzero status if any check fails. ```text src/main.c portable benchmark driver and scoring -src/fossmark.S ARM64 kernels -src/fossmark_x86_64.S x86-64 kernels -src/fossmark_i386.S i386 (Pentium 4) kernels -src/fossmark_ppc32.c PPC32/PPC64 big-endian kernels -src/fossmark_ppc32_ext.S optional PPC32 PS, VSX, and AltiVec kernels +src/fossbench.S ARM64 kernels +src/fossbench_x86_64.S x86-64 kernels +src/fossbench_i386.S i386 (Pentium 4) kernels +src/fossbench_ppc32.c PPC32/PPC64 big-endian kernels +src/fossbench_ppc32_ext.S optional PPC32 PS, VSX, and AltiVec kernels src/test_kernels.c correctness suite Makefile native and cross-build targets dist/ generated binaries diff --git a/src/fossmark.S b/src/fossbench.S similarity index 96% rename from src/fossmark.S rename to src/fossbench.S index 1e6751f..4cacb96 100644 --- a/src/fossmark.S +++ b/src/fossbench.S @@ -1,5 +1,5 @@ /* - * fossmark.S - AArch64 CPU benchmark kernels + * fossbench.S - AArch64 CPU benchmark kernels * * OS-independent: contains no syscalls, no libc calls, no relocations against * external data. Every routine is a pure function of its arguments under the @@ -51,14 +51,14 @@ .text /* =================================================================== - * uint64_t fm_int_math(uint64_t iters) + * uint64_t fb_int_math(uint64_t iters) * * Four largely independent accumulator chains to expose instruction-level * parallelism, mixed with high-latency serialising ops (udiv/sdiv) and the * bit-manipulation instructions. Returns a checksum so the compiler and the * driver cannot elide the work. * =================================================================== */ -FN_BEGIN(fm_int_math) +FN_BEGIN(fb_int_math) cbz x0, .Lim_zero MOV64(x1, 0x9E3779B97F4A7C15) /* a */ @@ -117,18 +117,18 @@ FN_BEGIN(fm_int_math) .Lim_zero: mov x0, xzr ret -FN_END(fm_int_math) +FN_END(fb_int_math) /* =================================================================== - * uint64_t fm_fp_math(uint64_t iters) + * uint64_t fb_fp_math(uint64_t iters) * * Double-precision scalar FP. Four fmadd chains cover the pipelined * multiply-add path; fdiv and fsqrt cover the non-pipelined divide/sqrt unit, * which is usually the real differentiator between cores. * Returns the result bit-cast to u64. * =================================================================== */ -FN_BEGIN(fm_fp_math) +FN_BEGIN(fb_fp_math) cbz x0, .Lfp_zero mov x6, x0 @@ -187,7 +187,7 @@ FN_BEGIN(fm_fp_math) .Lfp_zero: mov x0, xzr ret -FN_END(fm_fp_math) +FN_END(fb_fp_math) .p2align 4 .Lfp_consts: @@ -198,7 +198,7 @@ FN_END(fm_fp_math) /* =================================================================== - * uint64_t fm_primes(uint64_t limit, uint8_t *sieve) + * uint64_t fb_primes(uint64_t limit, uint8_t *sieve) * * Sieve of Eratosthenes over [0, limit). The caller supplies `limit` bytes of * scratch; this routine clears it itself, so the clearing pass is part of the @@ -207,7 +207,7 @@ FN_END(fm_fp_math) * Strided stores over a buffer larger than L1 make this a memory-hierarchy * test as much as an arithmetic one. * =================================================================== */ -FN_BEGIN(fm_primes) +FN_BEGIN(fb_primes) cmp x0, #2 b.lo .Lpr_none @@ -280,11 +280,11 @@ FN_BEGIN(fm_primes) .Lpr_none: mov x0, xzr ret -FN_END(fm_primes) +FN_END(fb_primes) /* =================================================================== - * uint64_t fm_simd(uint64_t iters, void *buf) + * uint64_t fb_simd(uint64_t iters, void *buf) * * "Extended instructions": the ASIMD/NEON unit, which is architecturally * mandatory on AArch64 and therefore safe to use without runtime feature @@ -294,7 +294,7 @@ FN_END(fm_primes) * * buf must be at least 128 bytes and 16-byte aligned. Returns a checksum. * =================================================================== */ -FN_BEGIN(fm_simd) +FN_BEGIN(fb_simd) cbz x0, .Lsd_zero mov x6, x0 @@ -394,7 +394,7 @@ FN_BEGIN(fm_simd) .Lsd_zero: mov x0, xzr ret -FN_END(fm_simd) +FN_END(fb_simd) .p2align 4 .Lsd_perm: @@ -402,7 +402,7 @@ FN_END(fm_simd) /* =================================================================== - * uint64_t fm_compress(const uint8_t *src, uint64_t len, uint32_t *ht) + * uint64_t fb_compress(const uint8_t *src, uint64_t len, uint32_t *ht) * * The match-finding inner loop of an LZ77 compressor (the LZ4 fast strategy): * hash the next 4 bytes, probe a single-entry-per-bucket table, verify, then @@ -412,7 +412,7 @@ FN_END(fm_simd) * ht must hold 1<<16 uint32_t (256 KiB); this routine clears it itself. * Returns the encoded size in bytes. * =================================================================== */ -FN_BEGIN(fm_compress) +FN_BEGIN(fb_compress) stp x29, x30, [sp, #-96]! mov x29, sp stp x19, x20, [sp, #16] @@ -523,11 +523,11 @@ FN_BEGIN(fm_compress) ldp x19, x20, [sp, #16] ldp x29, x30, [sp], #96 ret -FN_END(fm_compress) +FN_END(fb_compress) /* =================================================================== - * uint64_t fm_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], + * uint64_t fb_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], * uint64_t rounds) * * ChaCha20 stream cipher, NEON, four 128-bit state rows. Chosen over AES @@ -566,7 +566,7 @@ FN_END(fm_compress) VROTL_ASM \b, \b, v24, 7 .endm -FN_BEGIN(fm_chacha20) +FN_BEGIN(fb_chacha20) and x1, x1, #~63 /* whole 64-byte blocks only */ cbz x1, .Lcc_zero cbz x3, .Lcc_zero @@ -664,7 +664,7 @@ FN_BEGIN(fm_chacha20) .Lcc_zero: mov x0, xzr ret -FN_END(fm_chacha20) +FN_END(fb_chacha20) .p2align 4 .Lcc_sigma: @@ -672,7 +672,7 @@ FN_END(fm_chacha20) /* =================================================================== - * uint64_t fm_physics(double *bodies, uint64_t n, uint64_t steps) + * uint64_t fb_physics(double *bodies, uint64_t n, uint64_t steps) * * Direct-summation N-body gravity, O(n^2) per step, double precision. * Layout per body, 8 doubles (64 bytes, one cache line): @@ -682,7 +682,7 @@ FN_END(fm_chacha20) * so this exercises the divide/sqrt unit the way physics code actually does. * Returns a checksum bit-cast from the final velocity sum. * =================================================================== */ -FN_BEGIN(fm_physics) +FN_BEGIN(fb_physics) cbz x1, .Lph_zero cbz x2, .Lph_zero @@ -807,7 +807,7 @@ FN_BEGIN(fm_physics) .Lph_zero: mov x0, xzr ret -FN_END(fm_physics) +FN_END(fb_physics) .p2align 4 .Lph_consts: @@ -817,7 +817,7 @@ FN_END(fm_physics) /* =================================================================== - * uint64_t fm_sort(uint32_t *a, uint64_t n) + * uint64_t fb_sort(uint32_t *a, uint64_t n) * * In-place heapsort. Chosen over quicksort because it needs no recursion or * explicit stack, yet is aggressively branch-unpredictable and touches memory @@ -826,7 +826,7 @@ FN_END(fm_physics) * * Returns an order-sensitive checksum, which also verifies the sort. * =================================================================== */ -FN_BEGIN(fm_sort) +FN_BEGIN(fb_sort) cmp x1, #2 b.lo .Lst_trivial @@ -925,11 +925,11 @@ FN_BEGIN(fm_sort) .Lst_sift_done: ret -FN_END(fm_sort) +FN_END(fb_sort) /* =================================================================== - * uint64_t fm_chase(void **ptrs, uint64_t steps) + * uint64_t fb_chase(void **ptrs, uint64_t steps) * * Pointer chase around a randomised cycle. Every load depends on the previous * one, so nothing can be prefetched, overlapped or reordered - this measures @@ -937,7 +937,7 @@ FN_END(fm_sort) * hardest thing for a wide out-of-order core to hide. It is the truest * "single-threaded" test in the suite. * =================================================================== */ -FN_BEGIN(fm_chase) +FN_BEGIN(fb_chase) cbz x1, .Lch_zero mov x2, x0 /* p = ptrs */ mov x3, x1 @@ -953,7 +953,7 @@ FN_BEGIN(fm_chase) .Lch_zero: mov x0, xzr ret -FN_END(fm_chase) +FN_END(fb_chase) #if defined(__ELF__) diff --git a/src/fossmark_i386.S b/src/fossbench_i386.S similarity index 95% rename from src/fossmark_i386.S rename to src/fossbench_i386.S index 54b4f29..b733592 100644 --- a/src/fossmark_i386.S +++ b/src/fossbench_i386.S @@ -1,7 +1,7 @@ /* - * fossmark_i386.S - x86 32-bit (i386) CPU benchmark kernels + * fossbench_i386.S - x86 32-bit (i386) CPU benchmark kernels * - * The i386 counterpart to fossmark_x86_64.S. Same nine routines, same + * The i386 counterpart to fossbench_x86_64.S. Same nine routines, same * contract: each is a pure function of its arguments, contains no syscalls, * no libc calls and no external data relocations, so it assembles and runs * unmodified under the plain i386 SysV (cdecl) ABI on Linux. @@ -60,7 +60,7 @@ /* =================================================================== - * uint64_t fm_int_math(uint64_t iters) [ [esp+4]:[esp+8] = iters ] + * uint64_t fb_int_math(uint64_t iters) [ [esp+4]:[esp+8] = iters ] * * Four independent multiply-accumulate chains (a,b,c,d), each carried as a * hi:lo stack-frame pair since there's no register space left to hold four @@ -73,7 +73,7 @@ * hi/lo and does two native 32-bit `div`s - the same trick used to fix the * C fallback's __udivdi3 calls, now built directly into the kernel. * =================================================================== */ -FN_BEGIN(fm_int_math) +FN_BEGIN(fb_int_math) push ebp mov ebp, esp push ebx @@ -314,11 +314,11 @@ FN_BEGIN(fm_int_math) pop ebx pop ebp ret -FN_END(fm_int_math) +FN_END(fb_int_math) /* =================================================================== - * uint64_t fm_fp_math(uint64_t iters) [ [esp+4]:[esp+8] = iters ] + * uint64_t fb_fp_math(uint64_t iters) [ [esp+4]:[esp+8] = iters ] * * Double-precision scalar FP, genuine SSE2 throughout (Pentium 4's SSE2 unit * handles mulsd/addsd/minsd/maxsd/divsd/sqrtsd natively - there is no libm @@ -332,7 +332,7 @@ FN_END(fm_int_math) * u64 (edx:eax), matching the uint64_t return type - NOT via the x87 * ST(0) that a `double` return would use. * =================================================================== */ -FN_BEGIN(fm_fp_math) +FN_BEGIN(fb_fp_math) push ebp mov ebp, esp sub esp, 8 @@ -401,7 +401,7 @@ FN_BEGIN(fm_fp_math) xor edx, edx leave ret -FN_END(fm_fp_math) +FN_END(fb_fp_math) .p2align 4 .Lfp_a_init: @@ -426,7 +426,7 @@ FN_END(fm_fp_math) /* =================================================================== - * uint64_t fm_primes(uint64_t limit, uint8_t *sieve) + * uint64_t fb_primes(uint64_t limit, uint8_t *sieve) * [ [ebp+8]:[ebp+12]=limit, [ebp+16]=sieve ] * * Sieve of Eratosthenes over [0, limit). Only the low dword of `limit` is @@ -436,7 +436,7 @@ FN_END(fm_fp_math) * Clears its own scratch (32 bytes/iteration via SSE2), then sieves. Returns * the prime count in eax (edx=0: the count is always far under 2^32). * =================================================================== */ -FN_BEGIN(fm_primes) +FN_BEGIN(fb_primes) push ebp mov ebp, esp push ebx @@ -522,11 +522,11 @@ FN_BEGIN(fm_primes) pop ebx pop ebp ret -FN_END(fm_primes) +FN_END(fb_primes) /* =================================================================== - * uint64_t fm_simd(uint64_t iters, void *buf) + * uint64_t fb_simd(uint64_t iters, void *buf) * [ [ebp+8]:[ebp+12]=iters, [ebp+16]=buf ] * * "Extended instructions": SSE2, architecturally mandatory baseline for this @@ -542,7 +542,7 @@ FN_END(fm_primes) * * buf must be at least 96 bytes. Returns a checksum (edx=0). * =================================================================== */ -FN_BEGIN(fm_simd) +FN_BEGIN(fb_simd) push ebp mov ebp, esp push esi @@ -645,16 +645,16 @@ FN_BEGIN(fm_simd) pop esi pop ebp ret -FN_END(fm_simd) +FN_END(fb_simd) /* =================================================================== - * uint64_t fm_compress(const uint8_t *src, uint64_t len, uint32_t *ht) + * uint64_t fb_compress(const uint8_t *src, uint64_t len, uint32_t *ht) * [ [ebp+8]=src, [ebp+12]:[ebp+16]=len, [ebp+20]=ht ] * * The LZ77 fast-match inner loop (LZ4-style): hash the next 4 bytes, probe a * single-entry-per-bucket table, verify, then extend. Only the low dword of - * `len` is used (a buffer size - see fm_primes). This one has the tightest + * `len` is used (a buffer size - see fb_primes). This one has the tightest * register budget in the file: ip, ref, end and the match length all need * to be live across the byte-by-byte extend loop, which leaves nothing to * hold ht/src/anchor/mflimit/outsize in registers too, so those live on the @@ -664,7 +664,7 @@ FN_END(fm_simd) * ht must hold 1<<16 uint32_t (256 KiB); this routine clears it itself. * Returns the encoded size in bytes (edx=0). * =================================================================== */ -FN_BEGIN(fm_compress) +FN_BEGIN(fb_compress) push ebp mov ebp, esp push ebx @@ -788,11 +788,11 @@ FN_BEGIN(fm_compress) pop ebx pop ebp ret -FN_END(fm_compress) +FN_END(fb_compress) /* rotate each 32-bit lane of v left by n, via shift-left + shift-right + or. - * xmm7 is scratch (dedicated - see fm_chacha20's register map below). */ + * xmm7 is scratch (dedicated - see fb_chacha20's register map below). */ .macro ROL32_I386 v, n movdqa xmm7, \v pslld \v, \n @@ -817,22 +817,22 @@ FN_END(fm_compress) .endm /* =================================================================== - * uint64_t fm_chacha20(uint8_t *buf, uint64_t len, + * uint64_t fb_chacha20(uint8_t *buf, uint64_t len, * const uint8_t key[32], uint64_t passes) * [ [ebp+8]=buf, [ebp+12]:[ebp+16]=len, [ebp+20]=key, [ebp+24]:[ebp+28]=passes ] * * ChaCha20, SSE2, four 128-bit state rows - same 32-bit-mode register - * squeeze as fm_simd: xmm0-3 are the working state (rows A-D, mutated every + * squeeze as fb_simd: xmm0-3 are the working state (rows A-D, mutated every * round), xmm4-6 pin the constant/key base rows (re-copied into xmm0-2 each * block) and xmm7 is the ROL32 scratch - that is all eight xmm registers * with none left over, so unlike the amd64 file, the pre-round state (needed * for the feed-forward add) and the running keystream checksum live on the * stack instead of in xmm8-13. * - * len is rounded down to a multiple of 64 (buffer size - see fm_primes: low + * len is rounded down to a multiple of 64 (buffer size - see fb_primes: low * dword only). Returns a checksum of the keystream output (edx=0). * =================================================================== */ -FN_BEGIN(fm_chacha20) +FN_BEGIN(fb_chacha20) push ebp mov ebp, esp push ebx @@ -970,7 +970,7 @@ FN_BEGIN(fm_chacha20) pop ebx pop ebp ret -FN_END(fm_chacha20) +FN_END(fb_chacha20) .p2align 4 .Lcc_sigma: @@ -978,20 +978,20 @@ FN_END(fm_chacha20) /* =================================================================== - * uint64_t fm_physics(double *bodies, uint64_t n, uint64_t steps) + * uint64_t fb_physics(double *bodies, uint64_t n, uint64_t steps) * [ [ebp+8]=bodies, [ebp+12]:[ebp+16]=n, [ebp+20]:[ebp+24]=steps ] * * Direct-summation N-body gravity, O(n^2) per step, double precision, real * sqrtsd+divsd (not an rsqrt estimate). Layout per body, 8 doubles (64 * bytes): [x y z mass vx vy vz pad]. `n` uses only its low dword (a body - * count - see fm_primes). xmm0-2 hold body i's position for the whole inner + * count - see fb_primes). xmm0-2 hold body i's position for the whole inner * loop, xmm3-5 accumulate its acceleration, and xmm6-7 are the only scratch * left - not enough to hold dx/dy/dz simultaneously alongside r/1/r/m-over-r3, * so the three deltas spill to three stack doubles between being computed * and being used in the final ax+=dx*q step. Returns a velocity checksum * (edx=0). * =================================================================== */ -FN_BEGIN(fm_physics) +FN_BEGIN(fb_physics) push ebp mov ebp, esp push ebx @@ -1158,7 +1158,7 @@ FN_BEGIN(fm_physics) pop ebx pop ebp ret -FN_END(fm_physics) +FN_END(fb_physics) .p2align 4 .Lph_dt: @@ -1170,11 +1170,11 @@ FN_END(fm_physics) /* =================================================================== - * uint64_t fm_sort(uint32_t *a, uint64_t n) [ [ebp+8]=a, [ebp+12]:[ebp+16]=n ] + * uint64_t fb_sort(uint32_t *a, uint64_t n) [ [ebp+8]=a, [ebp+12]:[ebp+16]=n ] * * In-place heapsort, same shape as the amd64 file: no recursion, an * order-sensitive checksum that doubles as a correctness check. `n` uses - * only its low dword (an element count - see fm_primes). The internal + * only its low dword (an element count - see fb_primes). The internal * siftdown is reached with `call`/`ret` sharing this function's own frame * (no separate prologue) exactly like the amd64 version; it borrows ebx and * esi as scratch for the duration of one call via push/pop, since i386 has @@ -1183,7 +1183,7 @@ FN_END(fm_physics) * has no 64-bit rotate) - test_kernels.c only requires it be deterministic * and permutation-sensitive, which this is. * =================================================================== */ -FN_BEGIN(fm_sort) +FN_BEGIN(fb_sort) push ebp mov ebp, esp push ebx @@ -1300,11 +1300,11 @@ FN_BEGIN(fm_sort) pop esi pop ebx ret -FN_END(fm_sort) +FN_END(fb_sort) /* =================================================================== - * uint64_t fm_chase(void **ptrs, uint64_t steps) + * uint64_t fb_chase(void **ptrs, uint64_t steps) * [ [esp+4]=ptrs, [esp+8]:[esp+12]=steps ] * * Pointer chase around a randomised cycle. Every load depends on the @@ -1314,7 +1314,7 @@ FN_END(fm_sort) * kernel here it has no prologue - args stay at their original [esp+N] * offsets since esp never moves. * =================================================================== */ -FN_BEGIN(fm_chase) +FN_BEGIN(fb_chase) mov ecx, [esp+8] or ecx, [esp+12] jz .Lch_zero @@ -1336,7 +1336,7 @@ FN_BEGIN(fm_chase) xor eax, eax xor edx, edx ret -FN_END(fm_chase) +FN_END(fb_chase) #if defined(__ELF__) diff --git a/src/fossmark_ppc32.c b/src/fossbench_ppc32.c similarity index 85% rename from src/fossmark_ppc32.c rename to src/fossbench_ppc32.c index d20a191..aa3af65 100644 --- a/src/fossmark_ppc32.c +++ b/src/fossbench_ppc32.c @@ -20,7 +20,7 @@ static uint32_t rotl32(uint32_t x, unsigned n) return (x << n) | (x >> (32 - n)); } -uint64_t fm_int_math(uint64_t iters) +uint64_t fb_int_math(uint64_t iters) { uint64_t a = 0x9e3779b97f4a7c15ULL, b = 0xbf58476d1ce4e5b9ULL; uint64_t c = 0x94d049bb133111ebULL, d = 0x2545f4914f6cdd1dULL; @@ -35,7 +35,7 @@ uint64_t fm_int_math(uint64_t iters) return a ^ b ^ c ^ d; } -uint64_t fm_fp_math(uint64_t iters) +uint64_t fb_fp_math(uint64_t iters) { double a = 1.5, b = 2.5, c = 3.5, d = .5, out; uint64_t bits, i; @@ -52,7 +52,7 @@ uint64_t fm_fp_math(uint64_t iters) return bits; } -uint64_t fm_primes(uint64_t limit, uint8_t *sieve) +uint64_t fb_primes(uint64_t limit, uint8_t *sieve) { uint64_t i, j, count = 0; if (limit < 2) return 0; @@ -65,7 +65,7 @@ uint64_t fm_primes(uint64_t limit, uint8_t *sieve) } #if !defined(__powerpc64__) -static uint64_t fm_simd_scalar(uint64_t iters, void *memory) +static uint64_t fb_simd_scalar(uint64_t iters, void *memory) { uint32_t *v = (uint32_t *)memory; uint32_t a[8]; uint64_t i; unsigned j; uint32_t sum = 0; @@ -83,11 +83,11 @@ static uint64_t fm_simd_scalar(uint64_t iters, void *memory) /* The PowerPC 970 in every iMac G5 implements AltiVec. Using GCC's vector * type here lets the compiler handle whichever PPC64 ELF ABI the system uses; * both PPC64 ABIs differ from the PPC32 assembly convention below. */ -typedef uint32_t fm_vec_u32 __attribute__((vector_size(16))); +typedef uint32_t fb_vec_u32 __attribute__((vector_size(16))); -uint64_t fm_simd(uint64_t iters, void *memory) +uint64_t fb_simd(uint64_t iters, void *memory) { - fm_vec_u32 a, b; + fb_vec_u32 a, b; uint32_t *v = (uint32_t *)memory; uint32_t sum = 0; uint64_t i; @@ -110,13 +110,13 @@ uint64_t fm_simd(uint64_t iters, void *memory) return sum; } #else -/* These are kept in fossmark_ppc32_ext.S so this translation unit, and thus +/* These are kept in fossbench_ppc32_ext.S so this translation unit, and thus * the executable's default code path, only requires baseline PPC32. */ -extern void fm_simd_ps_kernel(uint64_t iters, void *memory); -extern void fm_simd_vsx_kernel(uint64_t iters, void *memory); -extern void fm_simd_altivec_kernel(uint64_t iters, void *memory); +extern void fb_simd_ps_kernel(uint64_t iters, void *memory); +extern void fb_simd_vsx_kernel(uint64_t iters, void *memory); +extern void fb_simd_altivec_kernel(uint64_t iters, void *memory); -typedef void (*fm_simd_kernel)(uint64_t, void *); +typedef void (*fb_simd_kernel)(uint64_t, void *); static int device_is_nintendo(void) { @@ -145,7 +145,7 @@ static int device_is_nintendo(void) #endif } -static fm_simd_kernel detect_simd_kernel(void) +static fb_simd_kernel detect_simd_kernel(void) { /* Linux exposes these in AT_HWCAP on both 32- and 64-bit PowerPC. * Spell out the ABI values instead of depending on kernel-only headers. */ @@ -155,23 +155,23 @@ static fm_simd_kernel detect_simd_kernel(void) const unsigned long has_vsx = 0x00000080UL; if (device_is_nintendo()) - return fm_simd_ps_kernel; + return fb_simd_ps_kernel; if (hwcap & has_vsx) - return fm_simd_vsx_kernel; + return fb_simd_vsx_kernel; if (hwcap & has_altivec) - return fm_simd_altivec_kernel; + return fb_simd_altivec_kernel; #else if (device_is_nintendo()) - return fm_simd_ps_kernel; + return fb_simd_ps_kernel; #endif return NULL; } -uint64_t fm_simd(uint64_t iters, void *memory) +uint64_t fb_simd(uint64_t iters, void *memory) { - static fm_simd_kernel kernel; + static fb_simd_kernel kernel; static int detected; - fm_simd_kernel selected; + fb_simd_kernel selected; uint32_t *v = (uint32_t *)memory; uint32_t sum = 0; unsigned j; @@ -179,13 +179,13 @@ uint64_t fm_simd(uint64_t iters, void *memory) if (!iters) return 0; if (!__atomic_load_n(&detected, __ATOMIC_ACQUIRE)) { - fm_simd_kernel found = detect_simd_kernel(); + fb_simd_kernel found = detect_simd_kernel(); __atomic_store_n(&kernel, found, __ATOMIC_RELAXED); __atomic_store_n(&detected, 1, __ATOMIC_RELEASE); } selected = __atomic_load_n(&kernel, __ATOMIC_RELAXED); if (selected == NULL) - return fm_simd_scalar(iters, memory); + return fb_simd_scalar(iters, memory); selected(iters, memory); for (j = 0; j < 8; j++) @@ -199,7 +199,7 @@ static uint32_t load32_native(const uint8_t *p) uint32_t v; memcpy(&v, p, sizeof v); return v; } -uint64_t fm_compress(const uint8_t *src, uint64_t len, uint32_t *ht) +uint64_t fb_compress(const uint8_t *src, uint64_t len, uint32_t *ht) { uint64_t ip = 0, anchor = 0, out = 0, ref, ml, lit; memset(ht, 0, (size_t)(1U << 16) * sizeof *ht); @@ -225,7 +225,7 @@ static void store32le(uint8_t *p, uint32_t v) p[0] = (uint8_t)v; p[1] = (uint8_t)(v >> 8); p[2] = (uint8_t)(v >> 16); p[3] = (uint8_t)(v >> 24); } #define QR(a,b,c,d) do { a+=b; d=rotl32(d^a,16); c+=d; b=rotl32(b^c,12); a+=b; d=rotl32(d^a,8); c+=d; b=rotl32(b^c,7); } while (0) -uint64_t fm_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], uint64_t passes) +uint64_t fb_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], uint64_t passes) { static const uint32_t sigma[4] = {0x61707865,0x3320646e,0x79622d32,0x6b206574}; uint32_t base[16], x[16], counter = 0, checksum = 0; uint64_t pass, off; int i, r; @@ -241,7 +241,7 @@ uint64_t fm_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], uint64_t } #undef QR -uint64_t fm_physics(double *b, uint64_t n, uint64_t steps) +uint64_t fb_physics(double *b, uint64_t n, uint64_t steps) { uint64_t s,i,j,bits; double sum=0; if (!n || !steps) return 0; @@ -253,7 +253,7 @@ uint64_t fm_physics(double *b, uint64_t n, uint64_t steps) } static void sift(uint32_t *a, uint64_t root, uint64_t end) { for (;;) { uint64_t c=root*2+1; uint32_t t; if(c>=end)return; if(c+1a[c])c++; if(a[root]>=a[c])return; t=a[root];a[root]=a[c];a[c]=t;root=c; } } -uint64_t fm_sort(uint32_t *a, uint64_t n) +uint64_t fb_sort(uint32_t *a, uint64_t n) { uint64_t i,end,sum=0; uint32_t t; if(n<2)return n?a[0]:0; for (i = n / 2; i; i--) @@ -265,7 +265,7 @@ uint64_t fm_sort(uint32_t *a, uint64_t n) for(i=0;i>7)|(sum<<57);sum^=a[i];sum+=a[i];} return sum; } -uint64_t fm_chase(void **ptrs, uint64_t steps) +uint64_t fb_chase(void **ptrs, uint64_t steps) { void **p=ptrs; uint64_t i; if(!steps)return 0; for(i=0;i @@ -38,51 +38,51 @@ # include #endif -/* Change this at build time with -DFM_API_BASE_URL=\"https://host\". */ -#ifndef FM_API_BASE_URL -# define FM_API_BASE_URL "https://fossbench.net" +/* Change this at build time with -DFB_API_BASE_URL=\"https://host\". */ +#ifndef FB_API_BASE_URL +# define FB_API_BASE_URL "https://fossbench.net" #endif -#define FM_VERSION "0.1.4" +#define FB_VERSION "0.1.4" /* ---------- platform identification (for the banner only) ---------- */ #if defined(_WIN32) -# define FM_OS "Windows" +# define FB_OS "Windows" #elif defined(__APPLE__) -# define FM_OS "macOS" +# define FB_OS "macOS" #elif defined(__linux__) -# define FM_OS "Linux" +# define FB_OS "Linux" #else -# define FM_OS "POSIX" +# define FB_OS "POSIX" #endif #if defined(__aarch64__) || defined(_M_ARM64) -# define FM_ARCH "ARM64" +# define FB_ARCH "ARM64" # define D_INT "64-bit ALU: madd, umulh, udiv, bitops" # define D_FP "double: fmadd, fdiv, fsqrt" # define D_SIMD "NEON ASIMD: 128-bit integer + float" #elif defined(__x86_64__) || defined(_M_X64) -# define FM_ARCH "x86-64" +# define FB_ARCH "x86-64" # define D_INT "64-bit ALU: imul, mul, div, bitops" # define D_FP "double: mulsd/addsd, divsd, sqrtsd" # define D_SIMD "SSE2: 128-bit integer + float" #elif defined(__i386__) || defined(_M_IX86) -# define FM_ARCH "x86 32-bit" +# define FB_ARCH "x86 32-bit" # define D_INT "Pentium 4 integer ALU and software 64-bit arithmetic" # define D_FP "x87 scalar double-precision floating point" # define D_SIMD "SSE2: 128-bit integer vectors" #elif defined(__powerpc64__) -# define FM_ARCH "PowerPC 64-bit big-endian" +# define FB_ARCH "PowerPC 64-bit big-endian" # define D_INT "64-bit PowerPC integer ALU" # define D_FP "PowerPC scalar double-precision floating point" # define D_SIMD "AltiVec: 128-bit integer vectors (PowerPC 970)" #elif defined(__powerpc__) -# define FM_ARCH "PowerPC 32-bit big-endian" +# define FB_ARCH "PowerPC 32-bit big-endian" # define D_INT "PPC32 integer ALU and software 64-bit arithmetic" # define D_FP "PowerPC scalar double-precision floating point" # define D_SIMD "runtime-selected PS, VSX, AltiVec, or scalar" #else -# define FM_ARCH "unknown" +# define FB_ARCH "unknown" # define D_INT "64-bit integer ALU" # define D_FP "double-precision FP" # define D_SIMD "128-bit SIMD: integer + float" @@ -124,16 +124,16 @@ static double now_seconds(void) /* ---------- the assembly kernels ---------- */ -extern uint64_t fm_int_math(uint64_t iters); -extern uint64_t fm_fp_math(uint64_t iters); -extern uint64_t fm_primes(uint64_t limit, uint8_t *sieve); -extern uint64_t fm_simd(uint64_t iters, void *buf); -extern uint64_t fm_compress(const uint8_t *src, uint64_t len, uint32_t *ht); -extern uint64_t fm_chacha20(uint8_t *buf, uint64_t len, +extern uint64_t fb_int_math(uint64_t iters); +extern uint64_t fb_fp_math(uint64_t iters); +extern uint64_t fb_primes(uint64_t limit, uint8_t *sieve); +extern uint64_t fb_simd(uint64_t iters, void *buf); +extern uint64_t fb_compress(const uint8_t *src, uint64_t len, uint32_t *ht); +extern uint64_t fb_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], uint64_t rounds); -extern uint64_t fm_physics(double *bodies, uint64_t n, uint64_t steps); -extern uint64_t fm_sort(uint32_t *a, uint64_t n); -extern uint64_t fm_chase(void **ptrs, uint64_t steps); +extern uint64_t fb_physics(double *bodies, uint64_t n, uint64_t steps); +extern uint64_t fb_sort(uint32_t *a, uint64_t n); +extern uint64_t fb_chase(void **ptrs, uint64_t steps); /* ---------- tuning ---------- */ @@ -166,51 +166,51 @@ extern uint64_t fm_chase(void **ptrs, uint64_t steps); * The overall score is a WEIGHTED geometric mean of each test's rate expressed * relative to a reference machine. Two knobs per test: * - * FM_REF_* the reference rate (this machine's measured rate). A machine - * matching the reference scores FM_TARGET_SCORE on that test. - * FM_WEIGHT_* how much that test counts toward the overall, by its + * FB_REF_* the reference rate (this machine's measured rate). A machine + * matching the reference scores FB_TARGET_SCORE on that test. + * FB_WEIGHT_* how much that test counts toward the overall, by its * influence on everyday user experience. Weights are relative: * only their ratios matter, so they need not sum to anything - * the code normalises by their sum. (They happen to sum to 100 * here, so each reads as a percent.) * - * Per-test score: S_i = FM_TARGET_SCORE * (rate_i / FM_REF_i) - * Overall score: Overall = FM_TARGET_SCORE * - * exp( Sum(w_i * ln(rate_i/FM_REF_i)) / Sum(w_i) ) + * Per-test score: S_i = FB_TARGET_SCORE * (rate_i / FB_REF_i) + * Overall score: Overall = FB_TARGET_SCORE * + * exp( Sum(w_i * ln(rate_i/FB_REF_i)) / Sum(w_i) ) * * On the reference machine every ratio is 1, so every S_i and the overall come - * out to exactly FM_TARGET_SCORE, regardless of the weights. Scaling is linear + * out to exactly FB_TARGET_SCORE, regardless of the weights. Scaling is linear * in performance, so far slower machines fall well below (half as fast -> half * the score) and faster future machines rise above. */ -#define FM_TARGET_SCORE 10000.0 /* reference-machine overall */ +#define FB_TARGET_SCORE 10000.0 /* reference-machine overall */ /* Reference rates: this machine, in each test's native unit (see tests[]). */ -#define FM_REF_INT 3086.0 /* Mops/s */ -#define FM_REF_FP 1682.0 /* Mops/s */ -#define FM_REF_PRIMES 812.0 /* Mcand/s */ -#define FM_REF_SIMD 6576.0 /* Mops/s */ -#define FM_REF_COMPRESS 674.0 /* MB/s */ -#define FM_REF_CRYPTO 406.0 /* MB/s */ -#define FM_REF_PHYSICS 631.0 /* Mpair/s */ -#define FM_REF_SORT 363.0 /* Mkey-cmp/s*/ -#define FM_REF_CHASE 79.0 /* Mhop/s (scoring); shown as ns/access */ +#define FB_REF_INT 3086.0 /* Mops/s */ +#define FB_REF_FP 1682.0 /* Mops/s */ +#define FB_REF_PRIMES 812.0 /* Mcand/s */ +#define FB_REF_SIMD 6576.0 /* Mops/s */ +#define FB_REF_COMPRESS 674.0 /* MB/s */ +#define FB_REF_CRYPTO 406.0 /* MB/s */ +#define FB_REF_PHYSICS 631.0 /* Mpair/s */ +#define FB_REF_SORT 363.0 /* Mkey-cmp/s*/ +#define FB_REF_CHASE 79.0 /* Mhop/s (scoring); shown as ns/access */ /* Weights: influence on day-to-day, common-workload user experience. * Rationale: integer/general-purpose code and memory-latency-bound * responsiveness dominate everyday use; specialised FP/physics matter least. * Roughly an 80/20 integer-vs-FP split, in the spirit of Geekbench 6's * weighted, integer-dominant methodology. Retune freely. */ -#define FM_WEIGHT_INT 20.0 /* general-purpose ALU: everything */ -#define FM_WEIGHT_CHASE 16.0 /* memory latency: responsiveness */ -#define FM_WEIGHT_COMPRESS 14.0 /* web, storage, RAM compression */ -#define FM_WEIGHT_SORT 12.0 /* general data-structure work */ -#define FM_WEIGHT_SIMD 11.0 /* codecs, mem/string ops, parsing */ -#define FM_WEIGHT_FP 9.0 /* spreadsheets, app/media math */ -#define FM_WEIGHT_CRYPTO 8.0 /* TLS, disk encryption (small frac) */ -#define FM_WEIGHT_PRIMES 6.0 /* synthetic ALU+memory proxy */ -#define FM_WEIGHT_PHYSICS 4.0 /* niche simulation/games */ +#define FB_WEIGHT_INT 20.0 /* general-purpose ALU: everything */ +#define FB_WEIGHT_CHASE 16.0 /* memory latency: responsiveness */ +#define FB_WEIGHT_COMPRESS 14.0 /* web, storage, RAM compression */ +#define FB_WEIGHT_SORT 12.0 /* general data-structure work */ +#define FB_WEIGHT_SIMD 11.0 /* codecs, mem/string ops, parsing */ +#define FB_WEIGHT_FP 9.0 /* spreadsheets, app/media math */ +#define FB_WEIGHT_CRYPTO 8.0 /* TLS, disk encryption (small frac) */ +#define FB_WEIGHT_PRIMES 6.0 /* synthetic ALU+memory proxy */ +#define FB_WEIGHT_PHYSICS 4.0 /* niche simulation/games */ /* ---------- deterministic PRNG (splitmix64) ---------- */ @@ -238,7 +238,7 @@ static void *xalloc(size_t n) p = NULL; #endif if (!p) { - fprintf(stderr, "fossmark: out of memory (%zu bytes)\n", n); + fprintf(stderr, "fossbench: out of memory (%zu bytes)\n", n); exit(1); } return p; @@ -331,8 +331,8 @@ static void detect_system_info(struct system_info *info) memset(info, 0, sizeof(*info)); info->cpu_threads = g_ncores; info->cpu_cores = g_ncores; - strncpy(info->cpu, FM_ARCH, sizeof(info->cpu) - 1); - strncpy(info->operating_system, FM_OS, sizeof(info->operating_system) - 1); + strncpy(info->cpu, FB_ARCH, sizeof(info->cpu) - 1); + strncpy(info->operating_system, FB_OS, sizeof(info->operating_system) - 1); #if defined(__clang__) snprintf(info->compiler, sizeof(info->compiler), "Clang %s", __clang_version__); #elif defined(__GNUC__) @@ -366,7 +366,7 @@ static void detect_system_info(struct system_info *info) if (!colon) continue; *colon++ = '\0'; trim(line); trim(colon); if ((!strcmp(line, "model name") || !strcmp(line, "Processor") || - !strcmp(line, "cpu")) && info->cpu[0] && !strcmp(info->cpu, FM_ARCH)) + !strcmp(line, "cpu")) && info->cpu[0] && !strcmp(info->cpu, FB_ARCH)) strncpy(info->cpu, colon, sizeof(info->cpu) - 1); else if (!strcmp(line, "Hardware") && cpuinfo_hardware[0] == '\0') strncpy(cpuinfo_hardware, colon, sizeof cpuinfo_hardware - 1); @@ -420,7 +420,7 @@ static void detect_system_info(struct system_info *info) size_t model_n = sizeof(info->model); int cores = 0; size_t cn = sizeof(cores); if (sysctlbyname("machdep.cpu.brand_string", info->cpu, &n, NULL, 0) != 0) - strncpy(info->cpu, FM_ARCH, sizeof info->cpu - 1); + strncpy(info->cpu, FB_ARCH, sizeof info->cpu - 1); sysctlbyname("hw.model", info->model, &model_n, NULL, 0); if (sysctlbyname("hw.physicalcpu", &cores, &cn, NULL, 0) == 0) info->cpu_cores = cores; if (sysctlbyname("hw.memsize", &mem, &mn, NULL, 0) == 0) info->memory_mb = (long)(mem / 1024 / 1024); @@ -582,18 +582,18 @@ struct test { static uint64_t run_int(uint64_t n, struct workspace *ws) { (void)ws; - return fm_int_math(n * 100000); + return fb_int_math(n * 100000); } static uint64_t run_fp(uint64_t n, struct workspace *ws) { (void)ws; - return fm_fp_math(n * 100000); + return fb_fp_math(n * 100000); } static uint64_t run_primes(uint64_t n, struct workspace *ws) { uint64_t c = 0; for (uint64_t i = 0; i < n; i++) - c += fm_primes(PRIME_LIMIT, ws->sieve); + c += fb_primes(PRIME_LIMIT, ws->sieve); return c; } static uint64_t run_simd(uint64_t n, struct workspace *ws) @@ -601,25 +601,25 @@ static uint64_t run_simd(uint64_t n, struct workspace *ws) /* The kernel is allowed to use its scratch as an accumulator. Restore it * before every timed run so calibration and repeats see identical input. */ memcpy(ws->simd_buf, g_simd_src, SIMD_BUF); - return fm_simd(n * 100000, ws->simd_buf); + return fb_simd(n * 100000, ws->simd_buf); } static uint64_t run_compress(uint64_t n, struct workspace *ws) { uint64_t c = 0; for (uint64_t i = 0; i < n; i++) - c += fm_compress(g_corpus, COMPRESS_LEN, ws->ht); + c += fb_compress(g_corpus, COMPRESS_LEN, ws->ht); return c; } static uint64_t run_crypto(uint64_t n, struct workspace *ws) { - return fm_chacha20(ws->cipher_buf, CIPHER_LEN, g_key, n); + return fb_chacha20(ws->cipher_buf, CIPHER_LEN, g_key, n); } static uint64_t run_physics(uint64_t n, struct workspace *ws) { /* restore initial conditions: the integrator mutates the bodies, so * a re-run must start from the same state to be reproducible */ memcpy(ws->bodies, g_bodies_src, NBODY_N * 8 * sizeof(double)); - return fm_physics(ws->bodies, NBODY_N, n); + return fb_physics(ws->bodies, NBODY_N, n); } static uint64_t run_sort(uint64_t n, struct workspace *ws) { @@ -628,43 +628,43 @@ static uint64_t run_sort(uint64_t n, struct workspace *ws) /* restore the pristine data: sorting an already-sorted array * would measure the best case, not the real one */ memcpy(ws->sort_work, g_sort_src, SORT_N * sizeof(uint32_t)); - c ^= fm_sort(ws->sort_work, SORT_N); + c ^= fb_sort(ws->sort_work, SORT_N); } return c; } static uint64_t run_chase(uint64_t n, struct workspace *ws) { - return fm_chase(ws->chase, n * 1000000); + return fb_chase(ws->chase, n * 1000000); } static const struct test tests[] = { { "Integer Math", D_INT, run_int, 20, 100000.0 * 24, "Mops/s", - FM_REF_INT, FM_WEIGHT_INT }, + FB_REF_INT, FB_WEIGHT_INT }, { "Floating Point Math", D_FP, run_fp, 20, 100000.0 * 20, "Mops/s", - FM_REF_FP, FM_WEIGHT_FP }, + FB_REF_FP, FB_WEIGHT_FP }, { "Prime Numbers", "sieve of Eratosthenes to 2M", run_primes, 1, (double)PRIME_LIMIT, "Mcand/s", - FM_REF_PRIMES, FM_WEIGHT_PRIMES }, + FB_REF_PRIMES, FB_WEIGHT_PRIMES }, { "Extended Instructions",D_SIMD, run_simd, 10, 100000.0 * 32, "Mops/s", - FM_REF_SIMD, FM_WEIGHT_SIMD }, + FB_REF_SIMD, FB_WEIGHT_SIMD }, { "Compression", "LZ77 match finder, 4 MiB corpus", run_compress, 1, (double)COMPRESS_LEN, "MB/s", - FM_REF_COMPRESS, FM_WEIGHT_COMPRESS }, + FB_REF_COMPRESS, FB_WEIGHT_COMPRESS }, { "Encryption", "ChaCha20, 20 rounds, 1 MiB", run_crypto, 4, (double)CIPHER_LEN, "MB/s", - FM_REF_CRYPTO, FM_WEIGHT_CRYPTO }, + FB_REF_CRYPTO, FB_WEIGHT_CRYPTO }, { "Physics", "512-body direct-sum gravity", run_physics, 4, (double)NBODY_N * NBODY_N, "Mpair/s", - FM_REF_PHYSICS, FM_WEIGHT_PHYSICS }, + FB_REF_PHYSICS, FB_WEIGHT_PHYSICS }, { "Sorting", "heapsort, 1M uint32", run_sort, 1, (double)SORT_N * 20, "Mkey-cmp/s", - FM_REF_SORT, FM_WEIGHT_SORT }, + FB_REF_SORT, FB_WEIGHT_SORT }, { "Memory Latency", CHASE_DETAIL, run_chase, 1, 1000000.0, "ns/access", - FM_REF_CHASE, FM_WEIGHT_CHASE }, + FB_REF_CHASE, FB_WEIGHT_CHASE }, }; #define NTESTS (sizeof(tests) / sizeof(tests[0])) @@ -773,7 +773,7 @@ static struct result run_test(const struct test *t, int threads) if (c != checksum) { fprintf(stderr, - "fossmark: %s is non-deterministic " + "fossbench: %s is non-deterministic " "(checksum %llu != %llu)\n", t->name, (unsigned long long)c, (unsigned long long)checksum); @@ -791,7 +791,7 @@ static struct result run_test(const struct test *t, int threads) * the same wall-clock window, so the machine's rate is their sum */ r.rate = ((double)threads * (double)n * t->work_per_n) / best / 1e6; /* normalise against the reference machine: this is the per-test score */ - r.score = FM_TARGET_SCORE * (r.rate / t->ref_rate); + r.score = FB_TARGET_SCORE * (r.rate / t->ref_rate); return r; } @@ -835,11 +835,12 @@ static void json_escape(const char *src, char *dst, size_t cap) #if !defined(_WIN32) static int upload_results(const struct system_info *info, double score, - uint64_t duration_ms) + uint64_t duration_ms, const char *token) { char host[256], port[16], path[512], payload[2048], request[4096]; + char auth_header[600]; char cpu[512], model[512], os[512], compiler[256], response[512]; - const char *base = FM_API_BASE_URL, *p, *slash, *colon; + const char *base = FB_API_BASE_URL, *p, *slash, *colon; struct addrinfo hints, *addresses = NULL, *a; SSL_CTX *tls_ctx = NULL; SSL *tls = NULL; @@ -874,17 +875,29 @@ static int upload_results(const struct system_info *info, double score, json_escape(info->model, model, sizeof(model)); json_escape(info->operating_system, os, sizeof(os)); json_escape(info->compiler, compiler, sizeof(compiler)); + /* "fossmark_version" is the API's field name, fixed by the server + * contract; it does not track this client's own product name. */ payload_len = snprintf(payload, sizeof(payload), "{\"cpu\":\"%s\",\"model\":\"%s\",\"cpu_cores\":%ld,\"cpu_threads\":%ld," "\"memory_mb\":%ld,\"operating_system\":\"%s\",\"compiler\":\"%s\"," "\"fossmark_version\":\"%s\",\"score\":%.2f,\"duration_ms\":%llu}", cpu, model, info->cpu_cores, info->cpu_threads, info->memory_mb, os, compiler, - FM_VERSION, score, (unsigned long long)duration_ms); + FB_VERSION, score, (unsigned long long)duration_ms); if (payload_len < 0 || (size_t)payload_len >= sizeof(payload)) return 0; + + auth_header[0] = '\0'; + if (token && token[0]) { + int n = snprintf(auth_header, sizeof(auth_header), + "Authorization: Bearer %s\r\n", token); + if (n < 0 || (size_t)n >= sizeof(auth_header)) { + fprintf(stderr, " upload error: API token too long\n"); + return 0; + } + } request_len = snprintf(request, sizeof(request), "POST %s HTTP/1.1\r\nHost: %s:%s\r\nContent-Type: application/json\r\n" - "Content-Length: %d\r\nConnection: close\r\n\r\n%s", - path, host, port, payload_len, payload); + "Content-Length: %d\r\nConnection: close\r\n%s\r\n%s", + path, host, port, payload_len, auth_header, payload); if (request_len < 0 || (size_t)request_len >= sizeof(request)) return 0; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; @@ -931,8 +944,19 @@ static int upload_results(const struct system_info *info, double score, if (tls) { SSL_shutdown(tls); SSL_free(tls); } if (tls_ctx) SSL_CTX_free(tls_ctx); close(fd); + if (status == 401) { + fprintf(stderr, " upload failed: API token was rejected (HTTP 401)\n"); + return 0; + } + if (status == 422) { + fprintf(stderr, " upload failed: server rejected the submission as invalid (HTTP 422)\n"); + return 0; + } if (status < 200 || status >= 300) { fprintf(stderr, " upload failed: server returned HTTP %d\n", status); return 0; } - printf(" Results uploaded successfully (HTTP %d).\n", status); + if (token) + printf(" Results uploaded and published to your profile (HTTP %d).\n", status); + else + printf(" Results uploaded, pending administrator review (HTTP %d).\n", status); return 1; upload_failed: @@ -948,13 +972,13 @@ upload_failed: static void print_header(const struct system_info *info) { printf("\n"); - printf(" fossbench %s - multi-core CPU benchmark\n", FM_VERSION); + printf(" fossbench %s - multi-core CPU benchmark\n", FB_VERSION); printf(" ------------------------------------------------------------------\n"); printf(" CPU: %s\n", info->cpu); printf(" model: %s\n", info->model[0] ? info->model : "unknown"); printf(" cores: %ld physical / %ld threads\n", info->cpu_cores, info->cpu_threads); printf(" memory: %ld MB\n", info->memory_mb); - printf(" OS: %s (%s)\n", info->operating_system, FM_ARCH); + printf(" OS: %s (%s)\n", info->operating_system, FB_ARCH); printf(" compiler: %s\n", info->compiler); printf("\n"); printf(" %-24s %12s %-11s %8s %9s\n", @@ -972,18 +996,31 @@ int main(int argc, char **argv) double benchmark_started, multicore_score, singlecore_score; uint64_t duration_ms; int verbose = 0; + int upload_mode = 0; /* 0 = ask, 1 = force upload, 2 = force no upload */ size_t i; for (i = 1; i < (size_t)argc; i++) { if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { verbose = 1; + } else if (strcmp(argv[i], "--upload") == 0) { + if (upload_mode == 2) { + fprintf(stderr, "fossbench: --upload conflicts with --noupload\n"); + return 1; + } + upload_mode = 1; + } else if (strcmp(argv[i], "--noupload") == 0) { + if (upload_mode == 1) { + fprintf(stderr, "fossbench: --noupload conflicts with --upload\n"); + return 1; + } + upload_mode = 2; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { - printf("usage: %s [-v|--verbose]\n", argv[0]); + printf("usage: %s [-v|--verbose] [--upload|--noupload]\n", argv[0]); return 0; } else { - fprintf(stderr, "fossmark: unknown option '%s'\n", + fprintf(stderr, "fossbench: unknown option '%s'\n", argv[i]); return 1; } @@ -1041,9 +1078,9 @@ int main(int argc, char **argv) /* * Two composite scores, each the WEIGHTED geometric mean of the per-test * scores from one pass. Per-test scores are already normalised so the - * single-thread reference machine reads FM_TARGET_SCORE. Geometric rather + * single-thread reference machine reads FB_TARGET_SCORE. Geometric rather * than arithmetic so no single test dominates; weighted so tests count in - * proportion to their influence on everyday use (the FM_WEIGHT_* config). + * proportion to their influence on everyday use (the FB_WEIGHT_* config). * The two passes share tests and weights, so MULTICORE / SINGLECORE is a * clean read of how much the machine gains from all its cores. */ @@ -1058,18 +1095,39 @@ int main(int argc, char **argv) teardown(); { - char answer[16]; - printf(" Upload this result to %s? [y/N] ", FM_API_BASE_URL); - fflush(stdout); - if (fgets(answer, sizeof(answer), stdin) && - (answer[0] == 'y' || answer[0] == 'Y')) { + /* the token is read from the environment only: it is never echoed + * back, so it never appears in argv, shell history, or process + * listings from a command-line flag */ + const char *token = getenv("FOSSBENCH_TOKEN"); + int do_upload; + + if (token && token[0] == '\0') + token = NULL; + + if (upload_mode == 1) { + do_upload = 1; + } else if (upload_mode == 2) { + do_upload = 0; + printf(" Result was not uploaded.\n"); + } else { + char answer[16]; + if (token) + printf(" Upload this result to %s using your API token? [y/N] ", FB_API_BASE_URL); + else + printf(" Upload this result to %s? [y/N] ", FB_API_BASE_URL); + fflush(stdout); + do_upload = fgets(answer, sizeof(answer), stdin) && + (answer[0] == 'y' || answer[0] == 'Y'); + if (!do_upload) + printf(" Result was not uploaded.\n"); + } + + if (do_upload) { #if defined(_WIN32) fprintf(stderr, " Upload is not yet supported on Windows.\n"); #else - upload_results(&system_info, multicore_score, duration_ms); + upload_results(&system_info, multicore_score, duration_ms, token); #endif - } else { - printf(" Result was not uploaded.\n"); } } return 0; diff --git a/src/test_kernels.c b/src/test_kernels.c index 9ae3595..7bf6d25 100644 --- a/src/test_kernels.c +++ b/src/test_kernels.c @@ -1,5 +1,5 @@ /* - * test_kernels.c - correctness checks for the fossmark assembly kernels + * test_kernels.c - correctness checks for the fossbench assembly kernels * * The benchmark's own best-of-N run guards against non-determinism, but a * kernel can be perfectly deterministic and still wrong. This file is the @@ -13,7 +13,7 @@ * matter how many copies run at once; a hidden global or a reentrancy bug would * survive a single-threaded run but fail here. * - * Build: cc -O2 -pthread test_kernels.c fossmark.S -o test_kernels -lm + * Build: cc -O2 -pthread test_kernels.c fossbench.S -o test_kernels -lm * Exit status is 0 iff every check passes. */ @@ -26,36 +26,36 @@ #include #include -extern uint64_t fm_int_math(uint64_t iters); -extern uint64_t fm_fp_math(uint64_t iters); -extern uint64_t fm_primes(uint64_t limit, uint8_t *sieve); -extern uint64_t fm_simd(uint64_t iters, void *buf); -extern uint64_t fm_compress(const uint8_t *src, uint64_t len, uint32_t *ht); -extern uint64_t fm_chacha20(uint8_t *buf, uint64_t len, +extern uint64_t fb_int_math(uint64_t iters); +extern uint64_t fb_fp_math(uint64_t iters); +extern uint64_t fb_primes(uint64_t limit, uint8_t *sieve); +extern uint64_t fb_simd(uint64_t iters, void *buf); +extern uint64_t fb_compress(const uint8_t *src, uint64_t len, uint32_t *ht); +extern uint64_t fb_chacha20(uint8_t *buf, uint64_t len, const uint8_t key[32], uint64_t rounds); -extern uint64_t fm_physics(double *bodies, uint64_t n, uint64_t steps); -extern uint64_t fm_sort(uint32_t *a, uint64_t n); -extern uint64_t fm_chase(void **ptrs, uint64_t steps); +extern uint64_t fb_physics(double *bodies, uint64_t n, uint64_t steps); +extern uint64_t fb_sort(uint32_t *a, uint64_t n); +extern uint64_t fb_chase(void **ptrs, uint64_t steps); static int failures = 0; static int checks = 0; /* * Concurrency plumbing. Each check runs on every core at once; the counters and - * stdout are shared, so ok()/note() serialise on this lock. `fm_primary` is set + * stdout are shared, so ok()/note() serialise on this lock. `fb_primary` is set * on exactly one thread per check (the one running on the main thread): it owns * the human-readable output so the "[ ok ]" lines and diagnostics appear once, * not once per core. Every thread still evaluates every assertion, so a failure * on any core - even a silent secondary - is reported and counted. */ static pthread_mutex_t io_lock = PTHREAD_MUTEX_INITIALIZER; -static __thread int fm_primary = 1; -static long fm_ncores = 1; +static __thread int fb_primary = 1; +static long fb_ncores = 1; static void ok(const char *what, int cond) { pthread_mutex_lock(&io_lock); - if (fm_primary) { + if (fb_primary) { checks++; if (cond) { printf(" [ ok ] %s\n", what); @@ -76,7 +76,7 @@ static void note(const char *fmt, ...) { va_list ap; - if (!fm_primary) + if (!fb_primary) return; pthread_mutex_lock(&io_lock); va_start(ap, fmt); @@ -86,19 +86,19 @@ static void note(const char *fmt, ...) } /* Run `check` on every core simultaneously. The main thread is the primary; - * fm_ncores-1 workers run the same check as silent secondaries. */ -static void *fm_worker(void *arg) + * fb_ncores-1 workers run the same check as silent secondaries. */ +static void *fb_worker(void *arg) { void (*check)(void) = *(void (**)(void))arg; - fm_primary = 0; + fb_primary = 0; check(); return NULL; } static void parallel(void (*check)(void)) { - long extra = fm_ncores - 1; + long extra = fb_ncores - 1; pthread_t *th = NULL; long i, spawned = 0; @@ -107,7 +107,7 @@ static void parallel(void (*check)(void)) if (th) { for (i = 0; i < extra; i++) if (pthread_create(&th[spawned], NULL, - fm_worker, &check) == 0) + fb_worker, &check) == 0) spawned++; } } @@ -186,39 +186,39 @@ static void check_int(void) { /* determinism and non-triviality: the checksum must be stable and * must actually change with the iteration count */ - uint64_t a = fm_int_math(1000); - uint64_t b = fm_int_math(1000); - uint64_t c = fm_int_math(2000); + uint64_t a = fb_int_math(1000); + uint64_t b = fb_int_math(1000); + uint64_t c = fb_int_math(2000); ok("int_math is deterministic", a == b); ok("int_math depends on iters", a != c); - ok("int_math(0) is zero", fm_int_math(0) == 0); + ok("int_math(0) is zero", fb_int_math(0) == 0); } static void check_fp(void) { - uint64_t a = fm_fp_math(1000); - uint64_t b = fm_fp_math(1000); + uint64_t a = fb_fp_math(1000); + uint64_t b = fb_fp_math(1000); double da; memcpy(&da, &a, sizeof da); ok("fp_math is deterministic", a == b); ok("fp_math result is finite", isfinite(da)); - ok("fp_math(0) is zero", fm_fp_math(0) == 0); + ok("fp_math(0) is zero", fb_fp_math(0) == 0); } static void check_primes(void) { enum { LIM = 1000000 }; uint8_t *sieve = malloc(LIM); - uint64_t got = fm_primes(LIM, sieve); + uint64_t got = fb_primes(LIM, sieve); uint64_t ref = ref_prime_count(LIM); note(" primes < %d: got %llu, expected %llu\n", LIM, (unsigned long long)got, (unsigned long long)ref); ok("primes matches reference sieve", got == ref); - ok("primes < 10 == 4", fm_primes(10, sieve) == 4); /* 2,3,5,7 */ - ok("primes < 2 == 0", fm_primes(2, sieve) == 0); + ok("primes < 10 == 4", fb_primes(10, sieve) == 4); /* 2,3,5,7 */ + ok("primes < 2 == 0", fb_primes(2, sieve) == 0); free(sieve); } @@ -228,11 +228,11 @@ static void check_simd(void) uint64_t a, b; memset(buf, 0xA5, 256); - a = fm_simd(500, buf); + a = fb_simd(500, buf); memset(buf, 0xA5, 256); - b = fm_simd(500, buf); + b = fb_simd(500, buf); ok("simd is deterministic", a == b); - ok("simd(0) is zero", fm_simd(0, buf) == 0); + ok("simd(0) is zero", fb_simd(0, buf) == 0); free(buf); } @@ -255,18 +255,18 @@ static void check_compress(void) src[i] = (uint8_t)(z ^ (z >> 31)); } } - incompressible = fm_compress(src, N, ht); + incompressible = fb_compress(src, N, ht); /* all-zero data is maximally compressible: it must shrink hugely */ memset(src, 0, N); - compressible = fm_compress(src, N, ht); + compressible = fb_compress(src, N, ht); note(" 64KiB random -> %llu bytes, 64KiB zeros -> %llu bytes\n", (unsigned long long)incompressible, (unsigned long long)compressible); ok("compress expands random data", incompressible >= N); ok("compress shrinks constant data", compressible < N / 10); - ok("compress is deterministic", fm_compress(src, N, ht) == compressible); + ok("compress is deterministic", fb_compress(src, N, ht) == compressible); free(src); free(ht); } @@ -308,7 +308,7 @@ static void check_crypto(void) for (i = 0; i < 32; i++) key[i] = (uint8_t)(i * 5 + 1); memset(buf, 0, sizeof buf); /* zeros -> raw keystream */ - fm_chacha20(buf, sizeof buf, key, 1); + fb_chacha20(buf, sizeof buf, key, 1); ref_chacha_block(ref0, key, 0, zero_nonce); ref_chacha_block(ref1, key, 1, zero_nonce); @@ -335,9 +335,9 @@ static void check_crypto(void) for (i = 0; i < 32; i++) k2[i] = (uint8_t)(i * 3); memcpy(work, plain, 128); - fm_chacha20(work, 128, k2, 1); + fb_chacha20(work, 128, k2, 1); ok("chacha20 actually changes data", memcmp(work, plain, 128) != 0); - fm_chacha20(work, 128, k2, 1); + fb_chacha20(work, 128, k2, 1); ok("chacha20 round-trips (XOR is involutive)", memcmp(work, plain, 128) == 0); } @@ -353,7 +353,7 @@ static void check_physics(void) bodies[0] = -1.0; bodies[3] = 1.0; /* body 0 at x=-1, mass 1 */ bodies[8] = 1.0; bodies[11] = 1.0; /* body 1 at x=+1, mass 1 */ - fm_physics(bodies, 2, 200); + fb_physics(bodies, 2, 200); /* velocities must be equal and opposite (Newton's third law) */ total_p = bodies[4] + bodies[12]; /* vx0 + vx1 */ @@ -393,7 +393,7 @@ static void check_sort(void) } memcpy(b, a, N * sizeof(uint32_t)); - s = fm_sort(a, N); + s = fb_sort(a, N); ok("sort produces sorted output", is_sorted(a, N)); /* multiset is preserved: sort the reference with the C library and @@ -404,12 +404,12 @@ static void check_sort(void) /* already-sorted input stays sorted and gives the same checksum */ { - uint64_t s2 = fm_sort(a, N); + uint64_t s2 = fb_sort(a, N); ok("sort is idempotent on sorted data", is_sorted(a, N) && s2 == s); } - ok("sort of empty array is zero", fm_sort(a, 0) == 0); + ok("sort of empty array is zero", fb_sort(a, 0) == 0); free(a); free(b); } @@ -425,25 +425,25 @@ static void check_chase(void) nodes[2] = &nodes[3]; nodes[3] = &nodes[0]; - /* 4 hops from &nodes[0] returns to &nodes[0]; fm_chase returns the + /* 4 hops from &nodes[0] returns to &nodes[0]; fb_chase returns the * final pointer minus the starting pointer, so a full loop gives 0 */ - ok("chase completes a full cycle", fm_chase(nodes, 4) == 0); - ok("chase(0) is zero", fm_chase(nodes, 0) == 0); + ok("chase completes a full cycle", fb_chase(nodes, 4) == 0); + ok("chase(0) is zero", fb_chase(nodes, 0) == 0); /* one hop lands on &nodes[1], i.e. one pointer-width past the start */ ok("chase single hop offset", - fm_chase(nodes, 1) == (uint64_t)((char *)&nodes[1] - (char *)&nodes[0])); + fb_chase(nodes, 1) == (uint64_t)((char *)&nodes[1] - (char *)&nodes[0])); } int main(void) { long n = sysconf(_SC_NPROCESSORS_ONLN); - fm_ncores = n > 0 ? n : 1; + fb_ncores = n > 0 ? n : 1; - printf("\nfossmark kernel correctness tests\n"); + printf("\nfossbench kernel correctness tests\n"); printf("=================================\n"); printf("running each check on %ld core%s in parallel\n\n", - fm_ncores, fm_ncores == 1 ? "" : "s"); + fb_ncores, fb_ncores == 1 ? "" : "s"); printf("Integer Math:\n"); parallel(check_int); printf("Floating Point Math:\n"); parallel(check_fp);