Add authenticated uploads and rename fossmark to fossbench

Uploads can now be attributed to a fossbench.net profile: set
FOSSBENCH_TOKEN and the client sends it as a Bearer token, which the
server auto-approves and links to the account. Anonymous, pending-review
upload stays the default when no token is set. New --upload/--noupload
flags skip the interactive prompt for scripted runs, and the client
reports HTTP 401/422 distinctly from other failures. The token is never
printed or logged.

Also renames the project and its internal identifiers (FM_/fm_ macros
and symbols, source filenames, binary output names) from fossmark to
fossbench, matching the actual product name. The "fossmark_version"
field in the upload payload is left as-is, since it's the server API's
fixed contract field, not this client's own name.
This commit is contained in:
2026-07-18 06:02:24 -05:00
parent 357e6f0d6d
commit ad5791bbb7
10 changed files with 406 additions and 336 deletions
+156 -98
View File
@@ -1,18 +1,18 @@
/*
* fossmark - a multi-core AArch64 CPU benchmark
* fossbench - a multi-core AArch64 CPU benchmark
*
* This file is the portable driver: it owns everything the assembly kernels
* deliberately do not (timing, memory, I/O, scoring). The kernels in
* fossmark.S are pure computation and identical on every OS; only this file
* fossbench.S are pure computation and identical on every OS; only this file
* knows what an operating system is.
*
* Every workload is run twice: once on a single core, and once on all available
* cores at once - one identical copy of the kernel per core, each with its own
* private buffers, so the machine is driven to 100%% and the rate is whole-machine
* throughput. From these two passes fossmark reports two composite scores, a
* throughput. From these two passes fossbench reports two composite scores, a
* SINGLECORE and a MULTICORE, from the same tests and the same weights.
*
* Build: cc -O2 -pthread main.c fossmark.S -o fossmark -lm
* Build: cc -O2 -pthread main.c fossbench.S -o fossbench -lm
*/
#include <stdio.h>
@@ -38,51 +38,51 @@
# include <mach/mach_time.h>
#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;