release 0.2.0

This commit is contained in:
2026-07-18 22:42:08 -05:00
parent 413dd3eb84
commit e585f509ac
4 changed files with 2141 additions and 2000 deletions
+80 -64
View File
@@ -1,26 +1,42 @@
> FOSSBench is ALPHA SOFTWARE, this means that scores reported from it should not be considered perfectly accurate. Across the machines we have tested (roughly 50 at the time of writing this) we have found it to be relatively accurate to what we would expect. This was more of a "for fun" project until someone confirms its validity on a larger scale.
# fossbench
fossbench is a CPU benchmarking tool thats fully open-source. The core idea is to build an open-source alternative to Passmark, Geekbench, and the like by providing our entire database for free to the public. Crowdsourcing the data to ensure its accuracy without any hidden strings being pulled behind the scenes.
fossbench - open source CPU benchmark
## Supported systems
## Synopsis
fossbench builds on Linux, macOS, and Windows for these architectures:
```sh
make
./dist/fossbench-<os>-<arch> [--verbose] [--no-system-check] [--upload | --noupload]
```
## Description
fossbench measures CPU and memory performance. Its source code and result
database are public. Uploaded results provide the comparison data.
Version 0.2 adds a 32-bit integer test and a 12 MiB STREAM triad per thread. It
keeps the old 64-bit test as the lower-weight wide integer test and changes the
score weights. Version 0.1 and 0.2 scores are not comparable.
## Systems
| Architecture | Baseline |
|---|---|
| ARM64 | ARMv8-A with NEON |
| x86-64 | baseline x86-64 with SSE2 |
| x86 32-bit | baseline i386 with SSE2 |
| PowerPC 32-bit big-endian | scalar fallback with runtime-selected extended instructions |
| PowerPC 64-bit big-endian | PowerPC 970 with AltiVec |
| x86-64 | x86-64 with SSE2 |
| x86 32-bit | i386 with SSE2 |
| PowerPC 32-bit, big-endian | scalar fallback with runtime-selected extensions |
| PowerPC 64-bit, big-endian | PowerPC 970 with AltiVec |
If you find something it doesnt run on, please make a PR with patches if you think you can make it!
Linux, macOS, and Windows are supported. Send a patch if a supported target
fails.
## Building
## Build
You need GNU Make, a C compiler, pthreads, and the system math library. Linux
and macOS builds also need OpenSSL headers and libraries. Windows uses WinHTTP
and does not depend on OpenSSL.
GNU Make, a C compiler, pthreads, and the system math library are required.
Linux and macOS also require OpenSSL. Windows uses WinHTTP.
Build for the current machine:
@@ -28,17 +44,14 @@ Build for the current machine:
make
```
The binary is written to `dist/fossbench-<os>-<arch>`. To build it and start a
benchmark immediately, run:
The output path is `dist/fossbench-<os>-<arch>`. Build and run it with:
```sh
make bench
```
Named targets are available when you want a specific build, these can be found in the Makefile.
Cross builds use conventional GNU toolchain names by default. Override a
compiler when your toolchain uses a different name:
The Makefile lists named build targets. Cross builds use standard GNU compiler
names. Override them when needed:
```sh
make linux-arm64 CC_ARM64=aarch64-linux-gnu-gcc
@@ -46,109 +59,112 @@ make linux-ppc32be CC_PPC32BE=powerpc-linux-gnu-gcc
make windows-amd64 CC_WINDOWS_AMD64=x86_64-w64-mingw32-gcc
```
The macOS AMD64 build defaults to macOS 10.5 compatibility. Set
`MACOS_AMD64_MIN` to choose another deployment target.
The macOS AMD64 target defaults to macOS 10.5. Set `MACOS_AMD64_MIN` to change
the deployment target.
## Running a benchmark
## Run
Run the binary directly. The exact name depends on your build:
Run the generated binary:
```sh
./dist/fossbench-linux-amd64
```
Useful options:
Options:
```text
--verbose print details for each workload
--no-system-check skip the startup system activity sample
--upload upload the result without prompting
--verbose print each workload
--no-system-check skip the startup activity sample
--upload upload without prompting
--noupload do not prompt or upload
```
Before a normal run, fossbench samples system activity for ten seconds. It
By default, fossbench samples system activity for ten seconds before a run. It
reports background CPU use, available memory, process count, and the OS kernel
or build. It does not collect process names or command lines.
Result uploads are optional and anonymous unless you provide an API token. To
attach a result to your fossbench.net account, create a benchmark client token
on the site and export it before running the benchmark:
Uploads are optional. They are anonymous without an API token. To attach a
result to a fossbench.net account, create a benchmark client token and export
it:
```sh
export FOSSBENCH_TOKEN=fb_your_token_here
./dist/fossbench-linux-amd64 --upload
```
You can point a build at another server with a compile-time definition:
Set another server at compile time:
```sh
make CFLAGS='-O2 -Wall -Wextra -DFB_API_BASE_URL=\"https://bench.example.com\"'
```
## What it measures
## Workloads
| Workload | Measurement |
|---|---|
| Integer math | 64-bit multiplication, division, shifts, and bit operations |
| Integer math | 32-bit multiply, divide, shifts, and bit operations |
| Wide integer | 64-bit multiply, divide, shifts, and bit operations |
| Floating point | scalar double-precision arithmetic |
| Prime numbers | sieve of Eratosthenes up to 2,000,000 |
| Extended instructions | 128-bit integer and floating point vector work |
| Compression | LZ77 match finding over a generated 4 MiB corpus |
| Encryption | ChaCha20 over a 1 MiB buffer |
| Prime numbers | sieve of Eratosthenes to 2,000,000 |
| Extended instructions | 128-bit integer and floating-point vector work |
| Compression | LZ77 match finding on a generated 4 MiB corpus |
| Encryption | ChaCha20 on a 1 MiB buffer |
| Physics | direct-sum gravity for 512 bodies |
| Sorting | in-place heapsort of one million 32-bit integers |
| Memory latency | dependent pointer chasing through a private cycle larger than cache |
| Memory latency | dependent pointer chasing through a cycle larger than cache |
| Memory bandwidth | STREAM triad with a 12 MiB working set per thread |
## Scores
A workload score compares its measured rate with a fixed reference rate:
Each workload uses a fixed reference rate:
```text
test score = 10000 * measured rate / reference rate
```
The single-core and multicore totals are weighted geometric means. Both passes
use the same references and weights.
Single-core and multicore totals are weighted geometric means. Both use the
same references and weights.
| Workload | Weight |
|---|---:|
| Integer math | 20% |
| Memory latency | 16% |
| Compression | 14% |
| Sorting | 12% |
| Extended instructions | 11% |
| Floating point | 9% |
| Integer math | 10% |
| Wide integer | 3% |
| Floating point | 10% |
| Prime numbers | 5% |
| Extended instructions | 16% |
| Compression | 12% |
| Encryption | 8% |
| Prime numbers | 6% |
| Physics | 4% |
| Physics | 3% |
| Sorting | 8% |
| Memory latency | 10% |
| Memory bandwidth | 15% |
The benchmark profile lives in `src/app/benchmark.c`. Changing its reference
rates, weights, workload sizes, calibration time, or repeat count makes scores
incompatible with the default build.
The benchmark profile is in `src/app/benchmark.c`. Changing its reference
rates, weights, workload sizes, calibration time, or repeat count makes its
scores incompatible with the default build.
Memory latency is printed in nanoseconds per access, though scoring uses the
underlying pointer-chase throughput. Memory placement and background operating
system work can move this result between runs.
Memory latency is shown in nanoseconds per access. Its score uses pointer-chase
throughput. Memory placement and background system work affect the result.
## Tests
The correctness suite compares the kernels with C implementations, known
answers, or invariants. It covers the RFC 8439 ChaCha20 vector, prime counts,
sorting, physics momentum, pointer chasing, deterministic output, and concurrent
execution.
Run the correctness suite:
```sh
make test
```
The command exits with a nonzero status when a check fails.
It checks kernels against C implementations, known answers, or invariants. It
covers ChaCha20 RFC 8439, prime counts, sorting, physics momentum, pointer
chasing, deterministic output, and concurrent execution. Failure returns a
nonzero status.
## Repository layout
## Files
```text
src/main.c command-line parsing and entrypoint
src/app/benchmark.c workload setup, timing, scoring, and run flow
src/app/benchmark.h function used by main.c
src/main.c option parsing and entry point
src/app/benchmark.c workloads, timing, scoring, and run flow
src/app/benchmark.h interface used by main.c
src/app/upload.c API payload and network transport
src/kernels/fossbench-arm64.S ARM64 kernels
src/kernels/fossbench-amd64.S x86-64 kernels
+82 -13
View File
@@ -16,8 +16,10 @@
#endif
#if !defined(_WIN32)
# include <sys/socket.h>
# include <sys/utsname.h>
#endif
#if !defined(_WIN32) && !defined(FB_NO_UPLOAD)
# include <sys/socket.h>
# include <netdb.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
@@ -38,7 +40,7 @@
#ifndef FB_API_BASE_URL
# define FB_API_BASE_URL "https://fossbench.net"
#endif
#define FB_VERSION "0.1.6"
#define FB_VERSION "0.2.0"
/* Names used in the header. */
@@ -142,6 +144,7 @@ extern uint64_t fb_chase(void **ptrs, uint64_t steps);
#define SIMD_BUF 256 /* Small SIMD buffer. */
#define NBODY_N 512 /* Number of physics bodies. */
#define SORT_N (1u << 20) /* Number of values to sort. */
#define STREAM_N (1u << 20) /* 12 MiB triad working set. */
/* Use less memory on 32-bit PowerPC. */
#if defined(__powerpc__) && !defined(__powerpc64__)
# define CHASE_NODES (1u << 19) /* Smaller pointer loop. */
@@ -163,6 +166,7 @@ extern uint64_t fb_chase(void **ptrs, uint64_t steps);
/* Rates from the reference machine. */
#define FB_REF_INT 3086.0 /* Reference rate. */
#define FB_REF_INT32 3086.0 /* Common 32-bit integer reference. */
#define FB_REF_FP 1682.0 /* Reference rate. */
#define FB_REF_PRIMES 812.0 /* Reference rate. */
#define FB_REF_SIMD 6576.0 /* Reference rate. */
@@ -171,17 +175,20 @@ extern uint64_t fb_chase(void **ptrs, uint64_t steps);
#define FB_REF_PHYSICS 631.0 /* Reference rate. */
#define FB_REF_SORT 363.0 /* Reference rate. */
#define FB_REF_CHASE 79.0 /* Memory test reference. */
#define FB_REF_STREAM 3200.0 /* STREAM triad reference rate. */
/* How much each test counts. */
#define FB_WEIGHT_INT 20.0 /* Score weight. */
#define FB_WEIGHT_CHASE 16.0 /* Score weight. */
#define FB_WEIGHT_COMPRESS 14.0 /* Score weight. */
#define FB_WEIGHT_SORT 12.0 /* Score weight. */
#define FB_WEIGHT_SIMD 11.0 /* Score weight. */
#define FB_WEIGHT_FP 9.0 /* Score weight. */
#define FB_WEIGHT_INT 3.0 /* Wide integer mix. */
#define FB_WEIGHT_INT32 10.0 /* Common native-width integer work. */
#define FB_WEIGHT_CHASE 10.0 /* Random-access latency. */
#define FB_WEIGHT_STREAM 15.0 /* Sustained memory bandwidth. */
#define FB_WEIGHT_COMPRESS 12.0 /* Score weight. */
#define FB_WEIGHT_SORT 8.0 /* Score weight. */
#define FB_WEIGHT_SIMD 16.0 /* Vector and packed arithmetic. */
#define FB_WEIGHT_FP 10.0 /* Score weight. */
#define FB_WEIGHT_CRYPTO 8.0 /* Score weight. */
#define FB_WEIGHT_PRIMES 6.0 /* Score weight. */
#define FB_WEIGHT_PHYSICS 4.0 /* Score weight. */
#define FB_WEIGHT_PRIMES 5.0 /* Score weight. */
#define FB_WEIGHT_PHYSICS 3.0 /* Divide/square-root-heavy. */
/* Simple repeatable random numbers. */
@@ -330,6 +337,7 @@ struct workspace {
double *bodies; /* n-body integration buffer. */
uint32_t *sort_work; /* the buffer we actually sort. */
void **chase; /* private 16 MiB pointer-chase cycle. */
float *stream_a, *stream_b, *stream_c;
};
static long g_ncores = 1; /* active online cores. */
@@ -640,10 +648,18 @@ static void setup(void)
w->bodies = xalloc(NBODY_N * 8 * sizeof(double));
w->sort_work = xalloc(SORT_N * sizeof(uint32_t));
w->chase = xalloc(CHASE_NODES * sizeof(void *));
w->stream_a = xalloc(STREAM_N * sizeof(float));
w->stream_b = xalloc(STREAM_N * sizeof(float));
w->stream_c = xalloc(STREAM_N * sizeof(float));
memcpy(w->cipher_buf, g_cipher_src, CIPHER_LEN);
memcpy(w->simd_buf, g_simd_src, SIMD_BUF);
build_chase(w->chase, CHASE_NODES);
for (i = 0; i < STREAM_N; i++) {
w->stream_a[i] = (float)(i & 1023) * (1.0f / 1024.0f);
w->stream_b[i] = (float)((i * 17) & 1023) * (1.0f / 1024.0f);
w->stream_c[i] = 0.0f;
}
}
}
@@ -657,6 +673,7 @@ static void teardown(void)
xfree(w->sieve); xfree(w->ht); xfree(w->cipher_buf);
xfree(w->simd_buf); xfree(w->bodies); xfree(w->sort_work);
xfree(w->chase);
xfree(w->stream_a); xfree(w->stream_b); xfree(w->stream_c);
}
xfree(g_ws);
@@ -685,6 +702,25 @@ static uint64_t run_int(uint64_t n, struct workspace *ws)
(void)ws;
return fb_int_math(n * 100000);
}
static uint64_t run_int32(uint64_t n, struct workspace *ws)
{
uint32_t a = 0x9e3779b9u, b = 0xbf58476du;
uint32_t c = 0x94d049bbu, d = 0x2545f491u;
uint64_t i, iters = n * 100000;
(void)ws;
for (i = 0; i < iters; i++) {
a = a * 0xdeadbeefu + b;
b = b * 0xdeadbeefu + c;
c = c * 0x9e3779b1u + d;
d = d * 0x9e3779b1u + a;
a ^= (c >> 7) | (c << 25);
b ^= (d >> 11) | (d << 21);
c ^= (a >> 17) | (a << 15);
d ^= (b >> 23) | (b << 9);
}
return (uint64_t)(a ^ b ^ c ^ d);
}
static uint64_t run_fp(uint64_t n, struct workspace *ws)
{
(void)ws;
@@ -735,8 +771,31 @@ static uint64_t run_chase(uint64_t n, struct workspace *ws)
return fb_chase(ws->chase, n * 1000000);
}
static uint64_t run_stream(uint64_t n, struct workspace *ws)
{
uint64_t pass, checksum = 0;
const float scale = 1.0009765625f;
for (pass = 0; pass < n; pass++) {
size_t i;
float *restrict a = ws->stream_a;
float *restrict b = ws->stream_b;
float *restrict c = ws->stream_c;
for (i = 0; i < STREAM_N; i++)
c[i] = a[i] + scale * b[i];
}
{
uint32_t bits;
memcpy(&bits, &ws->stream_c[(n * 104729u) & (STREAM_N - 1)], sizeof bits);
checksum = bits;
}
return checksum;
}
static const struct test tests[] = {
{ "Integer Math", D_INT,
{ "Native Integer Math", "common 32-bit multiply/add/rotate mix",
run_int32, 20, 100000.0 * 16, "Mops/s",
FB_REF_INT32, FB_WEIGHT_INT32 },
{ "Wide Integer Math", D_INT,
run_int, 20, 100000.0 * 24, "Mops/s",
FB_REF_INT, FB_WEIGHT_INT },
{ "Floating Point Math", D_FP,
@@ -763,6 +822,9 @@ static const struct test tests[] = {
{ "Memory Latency", CHASE_DETAIL,
run_chase, 1, 1000000.0, "ns/access",
FB_REF_CHASE, FB_WEIGHT_CHASE },
{ "Memory Bandwidth", "STREAM triad, 12 MiB working set per thread",
run_stream, 16, (double)STREAM_N * 12.0, "MB/s",
FB_REF_STREAM, FB_WEIGHT_STREAM },
};
#define NTESTS (sizeof(tests) / sizeof(tests[0]))
@@ -892,7 +954,9 @@ static double display_metric(const struct test *t, const struct result *r)
return r->rate;
}
#include "upload.c"
#if !defined(FB_NO_UPLOAD)
# include "upload.c"
#endif
/* Print the results. */
static void print_header(const struct system_info *info)
@@ -1029,9 +1093,14 @@ int fossbench_run(int verbose, int upload_mode, int system_check)
printf(" Result was not uploaded.\n");
}
if (do_upload)
if (do_upload) {
#if defined(FB_NO_UPLOAD)
fprintf(stderr, " Upload support is disabled in this build.\n");
#else
upload_results(&system_info, multicore_score, singlecore_score,
multi, single, duration_ms, &background, token);
#endif
}
}
return 0;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff