From 801fe88fbd1816ce4b15adb6ac6be0302782e992 Mon Sep 17 00:00:00 2001 From: Owen Rummage Date: Mon, 20 Jul 2026 18:15:02 -0500 Subject: [PATCH] weee --- Makefile | 20 ++--- README.md | 4 +- src/app/benchmark.c | 85 +++++++++++++----- src/app/hw_detect.c | 114 ++++++++++++++++++++++++ src/app/hw_detect.h | 3 + src/app/upload.c | 84 +++++++++++------- src/kernels/fossbench-i386.c | 145 +++++++++++++++++++++++++++++++ src/kernels/fossbench-portable.c | 19 ++++ 8 files changed, 409 insertions(+), 65 deletions(-) create mode 100644 src/kernels/fossbench-i386.c create mode 100644 src/kernels/fossbench-portable.c diff --git a/Makefile b/Makefile index 70eaef7..e487925 100644 --- a/Makefile +++ b/Makefile @@ -2,17 +2,17 @@ # Use make for the current computer, or a named target for another one. CC ?= cc -CFLAGS ?= -O2 -Wall -Wextra +CFLAGS ?= -O3 -flto -funroll-loops -Wall -Wextra LDLIBS ?= -lm # Needed for the worker threads. PTHREAD := -pthread DIST := dist -DRIVER := src/main.c src/app/benchmark.c src/app/hw_detect.c +DRIVER := src/main.c src/app/benchmark.c src/app/hw_detect.c src/kernels/fossbench-portable.c DRIVER_DEPS := src/app/benchmark.h src/app/hw_detect.h src/app/upload.c ASM_ARM64 := src/kernels/fossbench-arm64.S ASM_AMD64 := src/kernels/fossbench-amd64.S -ASM_I386 := src/kernels/fossbench-i386.S +SRC_I386 := src/kernels/fossbench-i386.c ASM_PPC32 := src/kernels/fossbench-ppc32be.S SRC_PPC32 := src/kernels/fossbench-ppc32be-chacha.c ASM_PPC64 := src/kernels/fossbench-ppc64be.S @@ -29,7 +29,7 @@ else ifneq (,$(filter x86_64 amd64,$(HOST_ARCH))) HOST_KERNEL := $(ASM_AMD64) else ifneq (,$(filter i386 i486 i586 i686 x86,$(HOST_ARCH))) HOST_ARCHNAME := i386 - HOST_KERNEL := $(ASM_I386) + HOST_KERNEL := $(SRC_I386) else ifneq (,$(filter ppc64le powerpc64le,$(HOST_ARCH))) HOST_ARCHNAME := ppc64le HOST_KERNEL := $(ASM_PPC64LE) @@ -47,8 +47,8 @@ else $(error unsupported host architecture '$(HOST_ARCH)') endif ifeq ($(HOST_ARCHNAME),i386) - # Keep the old i386 target simple and non-PIE. - CFLAGS += -march=pentium4 -fno-pie + # Keep the i386 target compatible with the original 80386 ISA. + CFLAGS += -march=i386 -fno-pie LDFLAGS += -no-pie endif ifeq ($(HOST_ARCHNAME),ppc64be) @@ -157,8 +157,8 @@ $(DIST)/fossbench-linux-amd64: $(DRIVER) $(DRIVER_DEPS) $(ASM_AMD64) | $(DIST) $(CC_AMD64) $(CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_AMD64) $(LDLIBS) @echo "built $@" -$(DIST)/fossbench-linux-i386: $(DRIVER) $(DRIVER_DEPS) $(ASM_I386) | $(DIST) - $(CC_I386) -m32 -march=pentium4 -fno-pie -no-pie $(CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(ASM_I386) $(LDLIBS) +$(DIST)/fossbench-linux-i386: $(DRIVER) $(DRIVER_DEPS) $(SRC_I386) | $(DIST) + $(CC_I386) -m32 -march=i386 -fno-pie -no-pie $(CFLAGS) $(PTHREAD) $(LDFLAGS) -o $@ $(DRIVER) $(SRC_I386) $(LDLIBS) @echo "built $@" $(DIST)/fossbench-linux-ppc32be: $(DRIVER) $(DRIVER_DEPS) $(ASM_PPC32) $(SRC_PPC32) | $(DIST) @@ -190,8 +190,8 @@ $(DIST)/fossbench-windows-amd64.exe: $(DRIVER) $(DRIVER_DEPS) $(ASM_AMD64) | $(D $(CC_WINDOWS_AMD64) $(CFLAGS) $(PTHREAD) -static -o $@ $(DRIVER) $(ASM_AMD64) -lm -lwinhttp -ladvapi32 @echo "built $@" -$(DIST)/fossbench-windows-i386.exe: $(DRIVER) $(DRIVER_DEPS) $(ASM_I386) | $(DIST) - $(CC_WINDOWS_I386) -march=pentium4 $(WINDOWS_I386_XP_CFLAGS) $(CFLAGS) -static $(WINDOWS_I386_XP_LDFLAGS) -o $@ $(DRIVER) $(ASM_I386) -lm -lwinhttp -ladvapi32 +$(DIST)/fossbench-windows-i386.exe: $(DRIVER) $(DRIVER_DEPS) $(SRC_I386) | $(DIST) + $(CC_WINDOWS_I386) -march=i386 $(WINDOWS_I386_XP_CFLAGS) $(CFLAGS) -static $(WINDOWS_I386_XP_LDFLAGS) -o $@ $(DRIVER) $(SRC_I386) -lm -lwinhttp -ladvapi32 @echo "built $@" # Add a native rule if one was not already made above. diff --git a/README.md b/README.md index 8d153ad..8ac8650 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ score weights. Version 0.1 and 0.2 scores are not comparable. |---|---| | ARM64 | ARMv8-A with NEON | | x86-64 | x86-64 with SSE2 | -| x86 32-bit | i386 with SSE2 | +| x86 32-bit | original i386 ISA (scalar fallback) | | PowerPC 32-bit, big-endian | scalar fallback with runtime-selected extensions | | PowerPC 64-bit, big-endian | PowerPC 970 with AltiVec | | PowerPC 32-bit, little-endian | scalar fallback with runtime-selected extensions | @@ -171,7 +171,7 @@ 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 -src/kernels/fossbench-i386.S i386 kernels +src/kernels/fossbench-i386.c portable scalar i386 kernels src/kernels/fossbench-ppc32be.S 32-bit big-endian PowerPC kernels src/kernels/fossbench-ppc64be.S 64-bit big-endian PowerPC kernels src/kernels/fossbench-ppc32le.S 32-bit little-endian PowerPC kernels diff --git a/src/app/benchmark.c b/src/app/benchmark.c index 70c6154..76bd393 100644 --- a/src/app/benchmark.c +++ b/src/app/benchmark.c @@ -38,7 +38,7 @@ #ifndef FB_API_BASE_URL # define FB_API_BASE_URL "http://fossbench.net" #endif -#define FB_VERSION "0.3.0" +#define FB_VERSION "0.4.0" /* * Native Integer Math and Memory Bandwidth are the only two *measured* @@ -70,9 +70,9 @@ # define D_FP "double: mulsd/addsd, divsd, sqrtsd" # define D_SIMD "SSE2: 128-bit integer + float" #elif defined(__i386__) || defined(_M_IX86) -# define D_INT "Pentium 4 integer ALU and software 64-bit arithmetic" +# define D_INT "i386 integer ALU and software 64-bit arithmetic" # define D_FP "x87 scalar double-precision floating point" -# define D_SIMD "SSE2: 128-bit integer vectors" +# define D_SIMD "scalar extended-instruction fallback" #elif defined(__powerpc64__) # define D_INT "64-bit PowerPC integer ALU" # define D_FP "PowerPC scalar double-precision floating point" @@ -132,6 +132,18 @@ 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); +/* GCC/Clang optimised C copies used for the REAL score. */ +extern uint64_t fb_c_int_math(uint64_t iters); +extern uint64_t fb_c_fp_math(uint64_t iters); +extern uint64_t fb_c_primes(uint64_t limit, uint8_t *sieve); +extern uint64_t fb_c_simd(uint64_t iters, void *buf); +extern uint64_t fb_c_compress(const uint8_t *src, uint64_t len, uint32_t *ht); +extern uint64_t fb_c_chacha20(uint8_t *buf, uint64_t len, + const uint8_t key[32], uint64_t rounds); +extern uint64_t fb_c_physics(double *bodies, uint64_t n, uint64_t steps); +extern uint64_t fb_c_sort(uint32_t *a, uint64_t n); +extern uint64_t fb_c_chase(void **ptrs, uint64_t steps); + /* Test sizes and timing settings. */ #define PRIME_LIMIT (2u * 1000u * 1000u) /* Prime test size. */ @@ -320,6 +332,7 @@ static uint8_t *g_cipher_src; /* pristine plaintext, copied per-core. */ static uint8_t *g_simd_src; /* pristine NEON seed, copied per-core. */ static double *g_bodies_src; /* pristine initial conditions. */ static uint32_t *g_sort_src; /* pristine unsorted data. */ +static int g_c_backend; /* zero = RAW assembly, one = REAL C. */ /* Synthesise a compressible corpus. */ @@ -466,7 +479,7 @@ struct test { static uint64_t run_int(uint64_t n, struct workspace *ws) { (void)ws; - return fb_int_math(n * 100000); + return g_c_backend ? fb_c_int_math(n * 100000) : fb_int_math(n * 100000); } FB_SCALAR_KERNEL @@ -492,37 +505,42 @@ static uint64_t run_int32(uint64_t n, struct workspace *ws) static uint64_t run_fp(uint64_t n, struct workspace *ws) { (void)ws; - return fb_fp_math(n * 100000); + return g_c_backend ? fb_c_fp_math(n * 100000) : 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 += fb_primes(PRIME_LIMIT, ws->sieve); + c += g_c_backend ? fb_c_primes(PRIME_LIMIT, ws->sieve) : + fb_primes(PRIME_LIMIT, ws->sieve); return c; } static uint64_t run_simd(uint64_t n, struct workspace *ws) { /* Reset the SIMD buffer before running. */ memcpy(ws->simd_buf, g_simd_src, SIMD_BUF); - return fb_simd(n * 100000, ws->simd_buf); + return g_c_backend ? fb_c_simd(n * 100000, ws->simd_buf) : + 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 += fb_compress(g_corpus, COMPRESS_LEN, ws->ht); + c += g_c_backend ? fb_c_compress(g_corpus, COMPRESS_LEN, ws->ht) : + fb_compress(g_corpus, COMPRESS_LEN, ws->ht); return c; } static uint64_t run_crypto(uint64_t n, struct workspace *ws) { - return fb_chacha20(ws->cipher_buf, CIPHER_LEN, g_key, n); + return g_c_backend ? fb_c_chacha20(ws->cipher_buf, CIPHER_LEN, g_key, n) : + fb_chacha20(ws->cipher_buf, CIPHER_LEN, g_key, n); } static uint64_t run_physics(uint64_t n, struct workspace *ws) { /* Reset the physics data before running. */ memcpy(ws->bodies, g_bodies_src, NBODY_N * 8 * sizeof(double)); - return fb_physics(ws->bodies, NBODY_N, n); + return g_c_backend ? fb_c_physics(ws->bodies, NBODY_N, n) : + fb_physics(ws->bodies, NBODY_N, n); } static uint64_t run_sort(uint64_t n, struct workspace *ws) { @@ -530,13 +548,15 @@ static uint64_t run_sort(uint64_t n, struct workspace *ws) for (uint64_t i = 0; i < n; i++) { /* Reset the sort data before running. */ memcpy(ws->sort_work, g_sort_src, SORT_N * sizeof(uint32_t)); - c ^= fb_sort(ws->sort_work, SORT_N); + c ^= g_c_backend ? fb_c_sort(ws->sort_work, SORT_N) : + fb_sort(ws->sort_work, SORT_N); } return c; } static uint64_t run_chase(uint64_t n, struct workspace *ws) { - return fb_chase(ws->chase, n * 1000000); + return g_c_backend ? fb_c_chase(ws->chase, n * 1000000) : + fb_chase(ws->chase, n * 1000000); } FB_SCALAR_KERNEL @@ -751,6 +771,8 @@ static void print_header(const struct system_info *info) 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(" caches: L1 %ld KB / L2 %ld KB / L3 %ld KB\n", + info->l1_cache_kb, info->l2_cache_kb, info->l3_cache_kb); printf(" OS: %s (%s)\n", info->operating_system, hw_arch_name()); printf(" kernel: %s\n", info->kernel[0] ? info->kernel : "unknown"); printf(" compiler: %s\n", info->compiler); @@ -763,7 +785,8 @@ static void print_header(const struct system_info *info) int fossbench_run(int verbose, int upload_mode, int system_check) { - struct result multi[NTESTS], single[NTESTS]; + struct result raw_multi[NTESTS], raw_single[NTESTS]; + struct result real_multi[NTESTS], real_single[NTESTS]; struct system_info system_info; struct background_metrics background; double benchmark_started; @@ -795,26 +818,47 @@ int fossbench_run(int verbose, int upload_mode, int system_check) print_header(&system_info); + printf(" RAW score suite (architecture assembly)\n"); + g_c_backend = 0; for (i = 0; i < NTESTS; i++) { printf(" %-24s", tests[i].name); fflush(stdout); /* Run every test with all cores and one core. */ - multi[i] = run_test(&tests[i], (int)g_ncores); - single[i] = run_test(&tests[i], 1); + raw_multi[i] = run_test(&tests[i], (int)g_ncores); + raw_single[i] = run_test(&tests[i], 1); printf(" %12.1f %-11s %7.2fs\n", - display_metric(&tests[i], &multi[i]), tests[i].unit, - multi[i].seconds); + display_metric(&tests[i], &raw_multi[i]), tests[i].unit, + raw_multi[i].seconds); if (verbose) printf(" %-24s %s\n" " %-24s 1-core: %.1f %s %ld-core: %.1f %s\n", "", tests[i].detail, "", - display_metric(&tests[i], &single[i]), tests[i].unit, - g_ncores, display_metric(&tests[i], &multi[i]), tests[i].unit); + display_metric(&tests[i], &raw_single[i]), tests[i].unit, + g_ncores, display_metric(&tests[i], &raw_multi[i]), tests[i].unit); fflush(stdout); } + printf(" --------------------------------------------------------------------------\n"); + printf(" REAL score suite (optimised portable C)\n"); + g_c_backend = 1; + for (i = 0; i < NTESTS; i++) { + printf(" %-24s", tests[i].name); + fflush(stdout); + real_multi[i] = run_test(&tests[i], (int)g_ncores); + real_single[i] = run_test(&tests[i], 1); + printf(" %12.1f %-11s %7.2fs\n", + display_metric(&tests[i], &real_multi[i]), tests[i].unit, + real_multi[i].seconds); + if (verbose) + printf(" %-24s %s\n" + " %-24s 1-core: %.1f %s %ld-core: %.1f %s\n", + "", tests[i].detail, "", + display_metric(&tests[i], &real_single[i]), tests[i].unit, + g_ncores, display_metric(&tests[i], &real_multi[i]), tests[i].unit); + } + printf(" --------------------------------------------------------------------------\n"); duration_ms = (uint64_t)((now_seconds() - benchmark_started) * 1000.0); @@ -845,7 +889,8 @@ int fossbench_run(int verbose, int upload_mode, int system_check) #if defined(FB_NO_UPLOAD) fprintf(stderr, " Upload support is disabled in this build.\n"); #else - upload_results(&system_info, multi, single, duration_ms, &background); + upload_results(&system_info, raw_multi, raw_single, + real_multi, real_single, duration_ms, &background); #endif } } diff --git a/src/app/hw_detect.c b/src/app/hw_detect.c index 571963c..684ba84 100644 --- a/src/app/hw_detect.c +++ b/src/app/hw_detect.c @@ -92,6 +92,39 @@ static int apple_m_name(const char *text, char *dst, size_t cap) /* Linux device trees identify Apple Silicon by its SoC code. */ #if defined(__linux__) +static int read_first_property(const char *path, char *dst, size_t cap); + +static long cache_size_kb(const char *text) +{ + char *end; + long value = strtol(text, &end, 10); + if (value <= 0) return 0; + while (*end && isspace((unsigned char)*end)) end++; + if (*end == 'M' || *end == 'm') value *= 1024; + return value; +} + +static void linux_detect_caches(struct system_info *info) +{ + int index; + for (index = 0; index < 32; index++) { + char path[160], level_text[32], size_text[32]; + long level, kb; + snprintf(path, sizeof path, + "/sys/devices/system/cpu/cpu0/cache/index%d/level", index); + if (!read_first_property(path, level_text, sizeof level_text)) continue; + snprintf(path, sizeof path, + "/sys/devices/system/cpu/cpu0/cache/index%d/size", index); + if (!read_first_property(path, size_text, sizeof size_text)) continue; + level = strtol(level_text, NULL, 10); + kb = cache_size_kb(size_text); + /* L1 instruction and data caches are separate and should be added. */ + if (level == 1) info->l1_cache_kb += kb; + else if (level == 2 && kb > info->l2_cache_kb) info->l2_cache_kb = kb; + else if (level == 3 && kb > info->l3_cache_kb) info->l3_cache_kb = kb; + } +} + static int apple_m_name_from_soc(const char *text, char *dst, size_t cap) { static const struct { const char *soc, *name; } chips[] = { @@ -505,6 +538,7 @@ void hw_detect_system(struct system_info *info) fclose(f); } } + linux_detect_caches(info); { FILE *f = fopen("/etc/os-release", "r"); char line[512]; if (f) { while (fgets(line, sizeof(line), f)) if (!strncmp(line, "PRETTY_NAME=", 12)) { @@ -540,6 +574,20 @@ void hw_detect_system(struct system_info *info) 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); + { + uint64_t bytes = 0; size_t bytes_n = sizeof bytes; + if (sysctlbyname("hw.l1dcachesize", &bytes, &bytes_n, NULL, 0) == 0) + info->l1_cache_kb += (long)(bytes / 1024); + bytes = 0; bytes_n = sizeof bytes; + if (sysctlbyname("hw.l1icachesize", &bytes, &bytes_n, NULL, 0) == 0) + info->l1_cache_kb += (long)(bytes / 1024); + bytes = 0; bytes_n = sizeof bytes; + if (sysctlbyname("hw.l2cachesize", &bytes, &bytes_n, NULL, 0) == 0) + info->l2_cache_kb = (long)(bytes / 1024); + bytes = 0; bytes_n = sizeof bytes; + if (sysctlbyname("hw.l3cachesize", &bytes, &bytes_n, NULL, 0) == 0) + info->l3_cache_kb = (long)(bytes / 1024); + } } { char product[64] = ""; size_t pn = sizeof(product); @@ -550,6 +598,30 @@ void hw_detect_system(struct system_info *info) snprintf(info->kernel, sizeof(info->kernel), "%.62s %.64s", u.sysname, u.release); } #elif defined(_WIN32) + { + DWORD bytes = 0; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION entries = NULL; + if (!GetLogicalProcessorInformation(NULL, &bytes) && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + entries = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(bytes); + if (entries && GetLogicalProcessorInformation(entries, &bytes)) { + DWORD i, count = bytes / sizeof *entries; + long cores = 0; + for (i = 0; i < count; i++) { + if (entries[i].Relationship == RelationProcessorCore) cores++; + else if (entries[i].Relationship == RelationCache) { + CACHE_DESCRIPTOR c = entries[i].Cache; + long kb = (long)(c.Size / 1024); + if (c.Level == 1 && kb > info->l1_cache_kb) info->l1_cache_kb = kb; + else if (c.Level == 2 && kb > info->l2_cache_kb) info->l2_cache_kb = kb; + else if (c.Level == 3 && kb > info->l3_cache_kb) info->l3_cache_kb = kb; + } + } + if (cores > 0) info->cpu_cores = cores; + } + free(entries); + } + } { HKEY key; char brand[sizeof info->cpu] = ""; @@ -571,6 +643,19 @@ void hw_detect_system(struct system_info *info) if (cores > 0) info->cpu_cores = cores; } + { + HKEY key; char product[sizeof info->model] = ""; + DWORD type = 0, bytes = sizeof product; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\BIOS", 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { + if (RegQueryValueExA(key, "SystemProductName", NULL, &type, + (BYTE *)product, &bytes) == ERROR_SUCCESS && type == REG_SZ) { + product[sizeof product - 1] = '\0'; trim(product); + if (product[0]) snprintf(info->model, sizeof info->model, "%s", product); + } + RegCloseKey(key); + } + } { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); @@ -617,4 +702,33 @@ void hw_detect_system(struct system_info *info) } #endif #endif + /* Portable POSIX fallbacks cover BSDs and other Unix systems where the + * platform-specific branches above are unavailable. */ +#if !defined(_WIN32) && !defined(__linux__) && !defined(__APPLE__) + { + long pages = sysconf(_SC_PHYS_PAGES), page_size = sysconf(_SC_PAGESIZE); + if (pages > 0 && page_size > 0) info->memory_mb = (pages / 1024) * (page_size / 1024); + } +# if defined(_SC_LEVEL1_DCACHE_SIZE) + { long v = sysconf(_SC_LEVEL1_DCACHE_SIZE); if (v > 0) info->l1_cache_kb += v / 1024; } +# endif +# if defined(_SC_LEVEL1_ICACHE_SIZE) + { long v = sysconf(_SC_LEVEL1_ICACHE_SIZE); if (v > 0) info->l1_cache_kb += v / 1024; } +# endif +# if defined(_SC_LEVEL2_CACHE_SIZE) + { long v = sysconf(_SC_LEVEL2_CACHE_SIZE); if (v > 0) info->l2_cache_kb = v / 1024; } +# endif +# if defined(_SC_LEVEL3_CACHE_SIZE) + { long v = sysconf(_SC_LEVEL3_CACHE_SIZE); if (v > 0) info->l3_cache_kb = v / 1024; } +# endif +#endif + /* Never emit empty identity fields: these values are used by the website + * for processor matching and display on platforms with sparse APIs. */ + if (!info->cpu[0]) snprintf(info->cpu, sizeof info->cpu, "%s", HW_ARCH); + if (!info->model[0]) snprintf(info->model, sizeof info->model, "%s", info->cpu); + if (!info->kernel[0]) snprintf(info->kernel, sizeof info->kernel, "%s", info->operating_system); + if (info->memory_mb < 1) info->memory_mb = 1; + if (info->l1_cache_kb < 1) info->l1_cache_kb = 1; + if (info->l2_cache_kb < 1) info->l2_cache_kb = info->l1_cache_kb; + if (info->l3_cache_kb < 1) info->l3_cache_kb = info->l2_cache_kb; } diff --git a/src/app/hw_detect.h b/src/app/hw_detect.h index b07c040..8c59f58 100644 --- a/src/app/hw_detect.h +++ b/src/app/hw_detect.h @@ -10,6 +10,9 @@ struct system_info { long cpu_cores; long cpu_threads; long memory_mb; + long l1_cache_kb; + long l2_cache_kb; + long l3_cache_kb; }; const char *hw_arch_name(void); diff --git a/src/app/upload.c b/src/app/upload.c index 34bd3a4..4e2e01c 100644 --- a/src/app/upload.c +++ b/src/app/upload.c @@ -120,18 +120,52 @@ done: } #endif +static int append_result_tests(char *payload, size_t cap, size_t *used, + const struct result *multi, + const struct result *single) +{ + static const char *ids[] = { + "native_integer", "wide_integer", "floating_point", "primes", + "extended_instructions", "compression", "encryption", "physics", + "sorting", "memory_latency", "memory_bandwidth" + }; + size_t i; + for (i = 0; i < NTESTS; i++) { + int n = snprintf(payload + *used, cap - *used, + "%s{\"id\":\"%s\",\"name\":\"%s\",\"detail\":\"%s\",\"unit\":\"%s\"," + "\"start_iterations\":%llu,\"work_per_iteration\":%.17g," + "\"multicore\":{\"display_metric\":%.17g,\"rate\":%.17g," + "\"seconds\":%.17g,\"iterations\":%llu,\"threads\":%d,\"checksum\":\"%llu\"}," + "\"singlecore\":{\"display_metric\":%.17g,\"rate\":%.17g," + "\"seconds\":%.17g,\"iterations\":%llu,\"threads\":%d,\"checksum\":\"%llu\"}}", + i ? "," : "", ids[i], tests[i].name, tests[i].detail, tests[i].unit, + (unsigned long long)tests[i].start_n, tests[i].work_per_n, + display_metric(&tests[i], &multi[i]), multi[i].rate, multi[i].seconds, + (unsigned long long)multi[i].iters, multi[i].threads, + (unsigned long long)multi[i].checksum, + display_metric(&tests[i], &single[i]), single[i].rate, single[i].seconds, + (unsigned long long)single[i].iters, single[i].threads, + (unsigned long long)single[i].checksum); + if (n < 0 || (size_t)n >= cap - *used) return 0; + *used += (size_t)n; + } + return 1; +} + static int upload_results(const struct system_info *info, - const struct result *multi, - const struct result *single, uint64_t duration_ms, + const struct result *raw_multi, + const struct result *raw_single, + const struct result *real_multi, + const struct result *real_single, uint64_t duration_ms, const struct background_metrics *background) { - char host[256], port[16], path[512], payload[16384]; + char host[256], port[16], path[512], payload[32768]; char auth_header[600], response_body[2048], claim_url[1024], result_url[1024]; char cpu[512], model[512], os[512], compiler[256], kernel[256]; const char *base = FB_API_BASE_URL, *p, *slash, *colon; int status = 0, payload_len; #if !defined(_WIN32) - char request[20000], response[4096]; + char request[40000], response[4096]; struct addrinfo hints, *addresses = NULL, *a; int fd = -1, request_len; #endif @@ -167,46 +201,30 @@ static int upload_results(const struct system_info *info, /* The server still calls this field fossmark_version. */ payload_len = snprintf(payload, sizeof(payload), "{\"cpu\":\"%s\",\"model\":\"%s\",\"cpu_cores\":%ld,\"cpu_threads\":%ld," + "\"architecture\":\"%s\",\"l1_cache_kb\":%ld,\"l2_cache_kb\":%ld,\"l3_cache_kb\":%ld," "\"memory_mb\":%ld,\"operating_system\":\"%s\",\"compiler\":\"%s\"," - "\"fossmark_version\":\"%s\",\"workload_suite\":\"fossbench-cpu-v1\"," + "\"fossmark_version\":\"%s\",\"workload_suite\":\"fossbench-cpu-v2\"," "\"duration_ms\":%llu,\"score_details\":{" "\"minimum_test_seconds\":%.17g,\"repeats\":%d," "\"system_environment\":{\"kernel\":\"%s\",\"sample_seconds\":%d," "\"background_cpu_average_percent\":%.17g,\"background_cpu_peak_percent\":%.17g," - "\"available_memory_mb\":%ld,\"process_count\":%ld},\"tests\":[", - cpu, model, info->cpu_cores, info->cpu_threads, info->memory_mb, os, compiler, + "\"available_memory_mb\":%ld,\"process_count\":%ld},\"raw_tests\":[", + cpu, model, info->cpu_cores, info->cpu_threads, hw_arch_name(), + info->l1_cache_kb, info->l2_cache_kb, info->l3_cache_kb, + info->memory_mb, os, compiler, FB_VERSION, (unsigned long long)duration_ms, MIN_SECONDS, REPEATS, kernel, background->samples, background->average_cpu_percent, background->peak_cpu_percent, background->available_memory_mb, background->process_count); if (payload_len < 0 || (size_t)payload_len >= sizeof(payload)) return 0; { size_t used = (size_t)payload_len; - size_t i; - for (i = 0; i < NTESTS; i++) { - static const char *ids[] = { - "native_integer", "wide_integer", "floating_point", "primes", - "extended_instructions", "compression", "encryption", "physics", - "sorting", "memory_latency", "memory_bandwidth" - }; - int n = snprintf(payload + used, sizeof(payload) - used, - "%s{\"id\":\"%s\",\"name\":\"%s\",\"detail\":\"%s\",\"unit\":\"%s\"," - "\"start_iterations\":%llu,\"work_per_iteration\":%.17g," - "\"multicore\":{\"display_metric\":%.17g,\"rate\":%.17g," - "\"seconds\":%.17g,\"iterations\":%llu,\"threads\":%d,\"checksum\":\"%llu\"}," - "\"singlecore\":{\"display_metric\":%.17g,\"rate\":%.17g," - "\"seconds\":%.17g,\"iterations\":%llu,\"threads\":%d,\"checksum\":\"%llu\"}}", - i ? "," : "", ids[i], tests[i].name, tests[i].detail, tests[i].unit, - (unsigned long long)tests[i].start_n, tests[i].work_per_n, - display_metric(&tests[i], &multi[i]), multi[i].rate, - multi[i].seconds, (unsigned long long)multi[i].iters, multi[i].threads, - (unsigned long long)multi[i].checksum, - display_metric(&tests[i], &single[i]), single[i].rate, - single[i].seconds, (unsigned long long)single[i].iters, single[i].threads, - (unsigned long long)single[i].checksum); - if (n < 0 || (size_t)n >= sizeof(payload) - used) return 0; - used += (size_t)n; - } - if (used + 3 >= sizeof(payload)) return 0; + int n; + if (!append_result_tests(payload, sizeof payload, &used, raw_multi, raw_single)) return 0; + n = snprintf(payload + used, sizeof payload - used, "],\"real_tests\":["); + if (n < 0 || (size_t)n >= sizeof payload - used) return 0; + used += (size_t)n; + if (!append_result_tests(payload, sizeof payload, &used, real_multi, real_single)) return 0; + if (used + 3 >= sizeof payload) return 0; memcpy(payload + used, "]}}", 4); payload_len = (int)(used + 3); } diff --git a/src/kernels/fossbench-i386.c b/src/kernels/fossbench-i386.c new file mode 100644 index 0000000..094d8bd --- /dev/null +++ b/src/kernels/fossbench-i386.c @@ -0,0 +1,145 @@ +/* Portable scalar backend for the baseline 32-bit x86 target. */ +#include +#include +#include +#include + +static uint32_t rotl32(uint32_t x, unsigned n) +{ + return (x << n) | (x >> (32 - n)); +} + +uint64_t fb_int_math(uint64_t iters) +{ + uint64_t a=0x9e3779b97f4a7c15ULL,b=0xbf58476d1ce4e5b9ULL; + uint64_t c=0x94d049bb133111ebULL,d=0x2545f4914f6cdd1dULL,i; + if (!iters) return 0; + for (i=0;i>29; b^=d<<17; c^=(a>>31)|(a<<33); d^=b>>7; + a+=c/0xdeadbeefU; b+=d/0xdeadbeefU; + } + return a^b^c^d; +} + +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; + if (!iters) return 0; + for (i=0;i>16; + ref=ht[h]; ht[h]=(uint32_t)ip; + if (ref>=ip||ip-ref>=65536||load32_native(src+ref)!=seq) { ip++; continue; } + for (ml=4;ip+ml=15)+(ml>=19); ip+=ml; anchor=ip; + } + return out+(len-anchor)+1; +} + +static uint32_t load32le(const uint8_t *p) +{ + return (uint32_t)p[0]|(uint32_t)p[1]<<8|(uint32_t)p[2]<<16|(uint32_t)p[3]<<24; +} +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 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; + len&=~(uint64_t)63; if (!len||!passes) return 0; + memcpy(base,sigma,16); for(i=0;i<8;i++) base[4+i]=load32le(key+4*i); + base[13]=base[14]=base[15]=0; + for(pass=0;pass=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 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--) sift(a,i-1,n); + for(end=n-1;end;end--) { t=a[0];a[0]=a[end];a[end]=t;sift(a,0,end); } + for(i=0;i>7)|(sum<<57);sum^=a[i];sum+=a[i];} return sum; +} + +uint64_t fb_chase(void **ptrs,uint64_t steps) +{ + void **p=ptrs; uint64_t i; if(!steps)return 0; for(i=0;i