119ea8026Sopenharmony_ci/* 219ea8026Sopenharmony_ci * Runner for littlefs benchmarks 319ea8026Sopenharmony_ci * 419ea8026Sopenharmony_ci * Copyright (c) 2022, The littlefs authors. 519ea8026Sopenharmony_ci * SPDX-License-Identifier: BSD-3-Clause 619ea8026Sopenharmony_ci */ 719ea8026Sopenharmony_ci#ifndef _POSIX_C_SOURCE 819ea8026Sopenharmony_ci#define _POSIX_C_SOURCE 199309L 919ea8026Sopenharmony_ci#endif 1019ea8026Sopenharmony_ci 1119ea8026Sopenharmony_ci#include "runners/bench_runner.h" 1219ea8026Sopenharmony_ci#include "bd/lfs_emubd.h" 1319ea8026Sopenharmony_ci 1419ea8026Sopenharmony_ci#include <getopt.h> 1519ea8026Sopenharmony_ci#include <sys/types.h> 1619ea8026Sopenharmony_ci#include <errno.h> 1719ea8026Sopenharmony_ci#include <setjmp.h> 1819ea8026Sopenharmony_ci#include <fcntl.h> 1919ea8026Sopenharmony_ci#include <stdarg.h> 2019ea8026Sopenharmony_ci#include <stdio.h> 2119ea8026Sopenharmony_ci#include <unistd.h> 2219ea8026Sopenharmony_ci#include <execinfo.h> 2319ea8026Sopenharmony_ci#include <time.h> 2419ea8026Sopenharmony_ci 2519ea8026Sopenharmony_ci 2619ea8026Sopenharmony_ci// some helpers 2719ea8026Sopenharmony_ci 2819ea8026Sopenharmony_ci// append to an array with amortized doubling 2919ea8026Sopenharmony_civoid *mappend(void **p, 3019ea8026Sopenharmony_ci size_t size, 3119ea8026Sopenharmony_ci size_t *count, 3219ea8026Sopenharmony_ci size_t *capacity) { 3319ea8026Sopenharmony_ci uint8_t *p_ = *p; 3419ea8026Sopenharmony_ci size_t count_ = *count; 3519ea8026Sopenharmony_ci size_t capacity_ = *capacity; 3619ea8026Sopenharmony_ci 3719ea8026Sopenharmony_ci count_ += 1; 3819ea8026Sopenharmony_ci if (count_ > capacity_) { 3919ea8026Sopenharmony_ci capacity_ = (2*capacity_ < 4) ? 4 : 2*capacity_; 4019ea8026Sopenharmony_ci 4119ea8026Sopenharmony_ci p_ = realloc(p_, capacity_*size); 4219ea8026Sopenharmony_ci if (!p_) { 4319ea8026Sopenharmony_ci return NULL; 4419ea8026Sopenharmony_ci } 4519ea8026Sopenharmony_ci } 4619ea8026Sopenharmony_ci 4719ea8026Sopenharmony_ci *p = p_; 4819ea8026Sopenharmony_ci *count = count_; 4919ea8026Sopenharmony_ci *capacity = capacity_; 5019ea8026Sopenharmony_ci return &p_[(count_-1)*size]; 5119ea8026Sopenharmony_ci} 5219ea8026Sopenharmony_ci 5319ea8026Sopenharmony_ci// a quick self-terminating text-safe varint scheme 5419ea8026Sopenharmony_cistatic void leb16_print(uintmax_t x) { 5519ea8026Sopenharmony_ci // allow 'w' to indicate negative numbers 5619ea8026Sopenharmony_ci if ((intmax_t)x < 0) { 5719ea8026Sopenharmony_ci printf("w"); 5819ea8026Sopenharmony_ci x = -x; 5919ea8026Sopenharmony_ci } 6019ea8026Sopenharmony_ci 6119ea8026Sopenharmony_ci while (true) { 6219ea8026Sopenharmony_ci char nibble = (x & 0xf) | (x > 0xf ? 0x10 : 0); 6319ea8026Sopenharmony_ci printf("%c", (nibble < 10) ? '0'+nibble : 'a'+nibble-10); 6419ea8026Sopenharmony_ci if (x <= 0xf) { 6519ea8026Sopenharmony_ci break; 6619ea8026Sopenharmony_ci } 6719ea8026Sopenharmony_ci x >>= 4; 6819ea8026Sopenharmony_ci } 6919ea8026Sopenharmony_ci} 7019ea8026Sopenharmony_ci 7119ea8026Sopenharmony_cistatic uintmax_t leb16_parse(const char *s, char **tail) { 7219ea8026Sopenharmony_ci bool neg = false; 7319ea8026Sopenharmony_ci uintmax_t x = 0; 7419ea8026Sopenharmony_ci if (tail) { 7519ea8026Sopenharmony_ci *tail = (char*)s; 7619ea8026Sopenharmony_ci } 7719ea8026Sopenharmony_ci 7819ea8026Sopenharmony_ci if (s[0] == 'w') { 7919ea8026Sopenharmony_ci neg = true; 8019ea8026Sopenharmony_ci s = s+1; 8119ea8026Sopenharmony_ci } 8219ea8026Sopenharmony_ci 8319ea8026Sopenharmony_ci size_t i = 0; 8419ea8026Sopenharmony_ci while (true) { 8519ea8026Sopenharmony_ci uintmax_t nibble = s[i]; 8619ea8026Sopenharmony_ci if (nibble >= '0' && nibble <= '9') { 8719ea8026Sopenharmony_ci nibble = nibble - '0'; 8819ea8026Sopenharmony_ci } else if (nibble >= 'a' && nibble <= 'v') { 8919ea8026Sopenharmony_ci nibble = nibble - 'a' + 10; 9019ea8026Sopenharmony_ci } else { 9119ea8026Sopenharmony_ci // invalid? 9219ea8026Sopenharmony_ci return 0; 9319ea8026Sopenharmony_ci } 9419ea8026Sopenharmony_ci 9519ea8026Sopenharmony_ci x |= (nibble & 0xf) << (4*i); 9619ea8026Sopenharmony_ci i += 1; 9719ea8026Sopenharmony_ci if (!(nibble & 0x10)) { 9819ea8026Sopenharmony_ci s = s + i; 9919ea8026Sopenharmony_ci break; 10019ea8026Sopenharmony_ci } 10119ea8026Sopenharmony_ci } 10219ea8026Sopenharmony_ci 10319ea8026Sopenharmony_ci if (tail) { 10419ea8026Sopenharmony_ci *tail = (char*)s; 10519ea8026Sopenharmony_ci } 10619ea8026Sopenharmony_ci return neg ? -x : x; 10719ea8026Sopenharmony_ci} 10819ea8026Sopenharmony_ci 10919ea8026Sopenharmony_ci 11019ea8026Sopenharmony_ci 11119ea8026Sopenharmony_ci// bench_runner types 11219ea8026Sopenharmony_ci 11319ea8026Sopenharmony_citypedef struct bench_geometry { 11419ea8026Sopenharmony_ci const char *name; 11519ea8026Sopenharmony_ci bench_define_t defines[BENCH_GEOMETRY_DEFINE_COUNT]; 11619ea8026Sopenharmony_ci} bench_geometry_t; 11719ea8026Sopenharmony_ci 11819ea8026Sopenharmony_citypedef struct bench_id { 11919ea8026Sopenharmony_ci const char *name; 12019ea8026Sopenharmony_ci const bench_define_t *defines; 12119ea8026Sopenharmony_ci size_t define_count; 12219ea8026Sopenharmony_ci} bench_id_t; 12319ea8026Sopenharmony_ci 12419ea8026Sopenharmony_ci 12519ea8026Sopenharmony_ci// bench suites are linked into a custom ld section 12619ea8026Sopenharmony_ciextern struct bench_suite __start__bench_suites; 12719ea8026Sopenharmony_ciextern struct bench_suite __stop__bench_suites; 12819ea8026Sopenharmony_ci 12919ea8026Sopenharmony_ciconst struct bench_suite *bench_suites = &__start__bench_suites; 13019ea8026Sopenharmony_ci#define BENCH_SUITE_COUNT \ 13119ea8026Sopenharmony_ci ((size_t)(&__stop__bench_suites - &__start__bench_suites)) 13219ea8026Sopenharmony_ci 13319ea8026Sopenharmony_ci 13419ea8026Sopenharmony_ci// bench define management 13519ea8026Sopenharmony_citypedef struct bench_define_map { 13619ea8026Sopenharmony_ci const bench_define_t *defines; 13719ea8026Sopenharmony_ci size_t count; 13819ea8026Sopenharmony_ci} bench_define_map_t; 13919ea8026Sopenharmony_ci 14019ea8026Sopenharmony_citypedef struct bench_define_names { 14119ea8026Sopenharmony_ci const char *const *names; 14219ea8026Sopenharmony_ci size_t count; 14319ea8026Sopenharmony_ci} bench_define_names_t; 14419ea8026Sopenharmony_ci 14519ea8026Sopenharmony_ciintmax_t bench_define_lit(void *data) { 14619ea8026Sopenharmony_ci return (intptr_t)data; 14719ea8026Sopenharmony_ci} 14819ea8026Sopenharmony_ci 14919ea8026Sopenharmony_ci#define BENCH_CONST(x) {bench_define_lit, (void*)(uintptr_t)(x)} 15019ea8026Sopenharmony_ci#define BENCH_LIT(x) ((bench_define_t)BENCH_CONST(x)) 15119ea8026Sopenharmony_ci 15219ea8026Sopenharmony_ci 15319ea8026Sopenharmony_ci#define BENCH_DEF(k, v) \ 15419ea8026Sopenharmony_ci intmax_t bench_define_##k(void *data) { \ 15519ea8026Sopenharmony_ci (void)data; \ 15619ea8026Sopenharmony_ci return v; \ 15719ea8026Sopenharmony_ci } 15819ea8026Sopenharmony_ci 15919ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINES 16019ea8026Sopenharmony_ci#undef BENCH_DEF 16119ea8026Sopenharmony_ci 16219ea8026Sopenharmony_ci#define BENCH_DEFINE_MAP_OVERRIDE 0 16319ea8026Sopenharmony_ci#define BENCH_DEFINE_MAP_EXPLICIT 1 16419ea8026Sopenharmony_ci#define BENCH_DEFINE_MAP_PERMUTATION 2 16519ea8026Sopenharmony_ci#define BENCH_DEFINE_MAP_GEOMETRY 3 16619ea8026Sopenharmony_ci#define BENCH_DEFINE_MAP_IMPLICIT 4 16719ea8026Sopenharmony_ci#define BENCH_DEFINE_MAP_COUNT 5 16819ea8026Sopenharmony_ci 16919ea8026Sopenharmony_cibench_define_map_t bench_define_maps[BENCH_DEFINE_MAP_COUNT] = { 17019ea8026Sopenharmony_ci [BENCH_DEFINE_MAP_IMPLICIT] = { 17119ea8026Sopenharmony_ci (const bench_define_t[BENCH_IMPLICIT_DEFINE_COUNT]) { 17219ea8026Sopenharmony_ci #define BENCH_DEF(k, v) \ 17319ea8026Sopenharmony_ci [k##_i] = {bench_define_##k, NULL}, 17419ea8026Sopenharmony_ci 17519ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINES 17619ea8026Sopenharmony_ci #undef BENCH_DEF 17719ea8026Sopenharmony_ci }, 17819ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT, 17919ea8026Sopenharmony_ci }, 18019ea8026Sopenharmony_ci}; 18119ea8026Sopenharmony_ci 18219ea8026Sopenharmony_ci#define BENCH_DEFINE_NAMES_SUITE 0 18319ea8026Sopenharmony_ci#define BENCH_DEFINE_NAMES_IMPLICIT 1 18419ea8026Sopenharmony_ci#define BENCH_DEFINE_NAMES_COUNT 2 18519ea8026Sopenharmony_ci 18619ea8026Sopenharmony_cibench_define_names_t bench_define_names[BENCH_DEFINE_NAMES_COUNT] = { 18719ea8026Sopenharmony_ci [BENCH_DEFINE_NAMES_IMPLICIT] = { 18819ea8026Sopenharmony_ci (const char *const[BENCH_IMPLICIT_DEFINE_COUNT]){ 18919ea8026Sopenharmony_ci #define BENCH_DEF(k, v) \ 19019ea8026Sopenharmony_ci [k##_i] = #k, 19119ea8026Sopenharmony_ci 19219ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINES 19319ea8026Sopenharmony_ci #undef BENCH_DEF 19419ea8026Sopenharmony_ci }, 19519ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT, 19619ea8026Sopenharmony_ci }, 19719ea8026Sopenharmony_ci}; 19819ea8026Sopenharmony_ci 19919ea8026Sopenharmony_ciintmax_t *bench_define_cache; 20019ea8026Sopenharmony_cisize_t bench_define_cache_count; 20119ea8026Sopenharmony_ciunsigned *bench_define_cache_mask; 20219ea8026Sopenharmony_ci 20319ea8026Sopenharmony_ciconst char *bench_define_name(size_t define) { 20419ea8026Sopenharmony_ci // lookup in our bench names 20519ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_DEFINE_NAMES_COUNT; i++) { 20619ea8026Sopenharmony_ci if (define < bench_define_names[i].count 20719ea8026Sopenharmony_ci && bench_define_names[i].names 20819ea8026Sopenharmony_ci && bench_define_names[i].names[define]) { 20919ea8026Sopenharmony_ci return bench_define_names[i].names[define]; 21019ea8026Sopenharmony_ci } 21119ea8026Sopenharmony_ci } 21219ea8026Sopenharmony_ci 21319ea8026Sopenharmony_ci return NULL; 21419ea8026Sopenharmony_ci} 21519ea8026Sopenharmony_ci 21619ea8026Sopenharmony_cibool bench_define_ispermutation(size_t define) { 21719ea8026Sopenharmony_ci // is this define specific to the permutation? 21819ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_DEFINE_MAP_IMPLICIT; i++) { 21919ea8026Sopenharmony_ci if (define < bench_define_maps[i].count 22019ea8026Sopenharmony_ci && bench_define_maps[i].defines[define].cb) { 22119ea8026Sopenharmony_ci return true; 22219ea8026Sopenharmony_ci } 22319ea8026Sopenharmony_ci } 22419ea8026Sopenharmony_ci 22519ea8026Sopenharmony_ci return false; 22619ea8026Sopenharmony_ci} 22719ea8026Sopenharmony_ci 22819ea8026Sopenharmony_ciintmax_t bench_define(size_t define) { 22919ea8026Sopenharmony_ci // is the define in our cache? 23019ea8026Sopenharmony_ci if (define < bench_define_cache_count 23119ea8026Sopenharmony_ci && (bench_define_cache_mask[define/(8*sizeof(unsigned))] 23219ea8026Sopenharmony_ci & (1 << (define%(8*sizeof(unsigned)))))) { 23319ea8026Sopenharmony_ci return bench_define_cache[define]; 23419ea8026Sopenharmony_ci } 23519ea8026Sopenharmony_ci 23619ea8026Sopenharmony_ci // lookup in our bench defines 23719ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_DEFINE_MAP_COUNT; i++) { 23819ea8026Sopenharmony_ci if (define < bench_define_maps[i].count 23919ea8026Sopenharmony_ci && bench_define_maps[i].defines[define].cb) { 24019ea8026Sopenharmony_ci intmax_t v = bench_define_maps[i].defines[define].cb( 24119ea8026Sopenharmony_ci bench_define_maps[i].defines[define].data); 24219ea8026Sopenharmony_ci 24319ea8026Sopenharmony_ci // insert into cache! 24419ea8026Sopenharmony_ci bench_define_cache[define] = v; 24519ea8026Sopenharmony_ci bench_define_cache_mask[define / (8*sizeof(unsigned))] 24619ea8026Sopenharmony_ci |= 1 << (define%(8*sizeof(unsigned))); 24719ea8026Sopenharmony_ci 24819ea8026Sopenharmony_ci return v; 24919ea8026Sopenharmony_ci } 25019ea8026Sopenharmony_ci } 25119ea8026Sopenharmony_ci 25219ea8026Sopenharmony_ci return 0; 25319ea8026Sopenharmony_ci 25419ea8026Sopenharmony_ci // not found? 25519ea8026Sopenharmony_ci const char *name = bench_define_name(define); 25619ea8026Sopenharmony_ci fprintf(stderr, "error: undefined define %s (%zd)\n", 25719ea8026Sopenharmony_ci name ? name : "(unknown)", 25819ea8026Sopenharmony_ci define); 25919ea8026Sopenharmony_ci assert(false); 26019ea8026Sopenharmony_ci exit(-1); 26119ea8026Sopenharmony_ci} 26219ea8026Sopenharmony_ci 26319ea8026Sopenharmony_civoid bench_define_flush(void) { 26419ea8026Sopenharmony_ci // clear cache between permutations 26519ea8026Sopenharmony_ci memset(bench_define_cache_mask, 0, 26619ea8026Sopenharmony_ci sizeof(unsigned)*( 26719ea8026Sopenharmony_ci (bench_define_cache_count+(8*sizeof(unsigned))-1) 26819ea8026Sopenharmony_ci / (8*sizeof(unsigned)))); 26919ea8026Sopenharmony_ci} 27019ea8026Sopenharmony_ci 27119ea8026Sopenharmony_ci// geometry updates 27219ea8026Sopenharmony_ciconst bench_geometry_t *bench_geometry = NULL; 27319ea8026Sopenharmony_ci 27419ea8026Sopenharmony_civoid bench_define_geometry(const bench_geometry_t *geometry) { 27519ea8026Sopenharmony_ci bench_define_maps[BENCH_DEFINE_MAP_GEOMETRY] = (bench_define_map_t){ 27619ea8026Sopenharmony_ci geometry->defines, BENCH_GEOMETRY_DEFINE_COUNT}; 27719ea8026Sopenharmony_ci} 27819ea8026Sopenharmony_ci 27919ea8026Sopenharmony_ci// override updates 28019ea8026Sopenharmony_citypedef struct bench_override { 28119ea8026Sopenharmony_ci const char *name; 28219ea8026Sopenharmony_ci const intmax_t *defines; 28319ea8026Sopenharmony_ci size_t permutations; 28419ea8026Sopenharmony_ci} bench_override_t; 28519ea8026Sopenharmony_ci 28619ea8026Sopenharmony_ciconst bench_override_t *bench_overrides = NULL; 28719ea8026Sopenharmony_cisize_t bench_override_count = 0; 28819ea8026Sopenharmony_ci 28919ea8026Sopenharmony_cibench_define_t *bench_override_defines = NULL; 29019ea8026Sopenharmony_cisize_t bench_override_define_count = 0; 29119ea8026Sopenharmony_cisize_t bench_override_define_permutations = 1; 29219ea8026Sopenharmony_cisize_t bench_override_define_capacity = 0; 29319ea8026Sopenharmony_ci 29419ea8026Sopenharmony_ci// suite/perm updates 29519ea8026Sopenharmony_civoid bench_define_suite(const struct bench_suite *suite) { 29619ea8026Sopenharmony_ci bench_define_names[BENCH_DEFINE_NAMES_SUITE] = (bench_define_names_t){ 29719ea8026Sopenharmony_ci suite->define_names, suite->define_count}; 29819ea8026Sopenharmony_ci 29919ea8026Sopenharmony_ci // make sure our cache is large enough 30019ea8026Sopenharmony_ci if (lfs_max(suite->define_count, BENCH_IMPLICIT_DEFINE_COUNT) 30119ea8026Sopenharmony_ci > bench_define_cache_count) { 30219ea8026Sopenharmony_ci // align to power of two to avoid any superlinear growth 30319ea8026Sopenharmony_ci size_t ncount = 1 << lfs_npw2( 30419ea8026Sopenharmony_ci lfs_max(suite->define_count, BENCH_IMPLICIT_DEFINE_COUNT)); 30519ea8026Sopenharmony_ci bench_define_cache = realloc(bench_define_cache, ncount*sizeof(intmax_t)); 30619ea8026Sopenharmony_ci bench_define_cache_mask = realloc(bench_define_cache_mask, 30719ea8026Sopenharmony_ci sizeof(unsigned)*( 30819ea8026Sopenharmony_ci (ncount+(8*sizeof(unsigned))-1) 30919ea8026Sopenharmony_ci / (8*sizeof(unsigned)))); 31019ea8026Sopenharmony_ci bench_define_cache_count = ncount; 31119ea8026Sopenharmony_ci } 31219ea8026Sopenharmony_ci 31319ea8026Sopenharmony_ci // map any overrides 31419ea8026Sopenharmony_ci if (bench_override_count > 0) { 31519ea8026Sopenharmony_ci // first figure out the total size of override permutations 31619ea8026Sopenharmony_ci size_t count = 0; 31719ea8026Sopenharmony_ci size_t permutations = 1; 31819ea8026Sopenharmony_ci for (size_t i = 0; i < bench_override_count; i++) { 31919ea8026Sopenharmony_ci for (size_t d = 0; 32019ea8026Sopenharmony_ci d < lfs_max( 32119ea8026Sopenharmony_ci suite->define_count, 32219ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT); 32319ea8026Sopenharmony_ci d++) { 32419ea8026Sopenharmony_ci // define name match? 32519ea8026Sopenharmony_ci const char *name = bench_define_name(d); 32619ea8026Sopenharmony_ci if (name && strcmp(name, bench_overrides[i].name) == 0) { 32719ea8026Sopenharmony_ci count = lfs_max(count, d+1); 32819ea8026Sopenharmony_ci permutations *= bench_overrides[i].permutations; 32919ea8026Sopenharmony_ci break; 33019ea8026Sopenharmony_ci } 33119ea8026Sopenharmony_ci } 33219ea8026Sopenharmony_ci } 33319ea8026Sopenharmony_ci bench_override_define_count = count; 33419ea8026Sopenharmony_ci bench_override_define_permutations = permutations; 33519ea8026Sopenharmony_ci 33619ea8026Sopenharmony_ci // make sure our override arrays are big enough 33719ea8026Sopenharmony_ci if (count * permutations > bench_override_define_capacity) { 33819ea8026Sopenharmony_ci // align to power of two to avoid any superlinear growth 33919ea8026Sopenharmony_ci size_t ncapacity = 1 << lfs_npw2(count * permutations); 34019ea8026Sopenharmony_ci bench_override_defines = realloc( 34119ea8026Sopenharmony_ci bench_override_defines, 34219ea8026Sopenharmony_ci sizeof(bench_define_t)*ncapacity); 34319ea8026Sopenharmony_ci bench_override_define_capacity = ncapacity; 34419ea8026Sopenharmony_ci } 34519ea8026Sopenharmony_ci 34619ea8026Sopenharmony_ci // zero unoverridden defines 34719ea8026Sopenharmony_ci memset(bench_override_defines, 0, 34819ea8026Sopenharmony_ci sizeof(bench_define_t) * count * permutations); 34919ea8026Sopenharmony_ci 35019ea8026Sopenharmony_ci // compute permutations 35119ea8026Sopenharmony_ci size_t p = 1; 35219ea8026Sopenharmony_ci for (size_t i = 0; i < bench_override_count; i++) { 35319ea8026Sopenharmony_ci for (size_t d = 0; 35419ea8026Sopenharmony_ci d < lfs_max( 35519ea8026Sopenharmony_ci suite->define_count, 35619ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT); 35719ea8026Sopenharmony_ci d++) { 35819ea8026Sopenharmony_ci // define name match? 35919ea8026Sopenharmony_ci const char *name = bench_define_name(d); 36019ea8026Sopenharmony_ci if (name && strcmp(name, bench_overrides[i].name) == 0) { 36119ea8026Sopenharmony_ci // scatter the define permutations based on already 36219ea8026Sopenharmony_ci // seen permutations 36319ea8026Sopenharmony_ci for (size_t j = 0; j < permutations; j++) { 36419ea8026Sopenharmony_ci bench_override_defines[j*count + d] = BENCH_LIT( 36519ea8026Sopenharmony_ci bench_overrides[i].defines[(j/p) 36619ea8026Sopenharmony_ci % bench_overrides[i].permutations]); 36719ea8026Sopenharmony_ci } 36819ea8026Sopenharmony_ci 36919ea8026Sopenharmony_ci // keep track of how many permutations we've seen so far 37019ea8026Sopenharmony_ci p *= bench_overrides[i].permutations; 37119ea8026Sopenharmony_ci break; 37219ea8026Sopenharmony_ci } 37319ea8026Sopenharmony_ci } 37419ea8026Sopenharmony_ci } 37519ea8026Sopenharmony_ci } 37619ea8026Sopenharmony_ci} 37719ea8026Sopenharmony_ci 37819ea8026Sopenharmony_civoid bench_define_perm( 37919ea8026Sopenharmony_ci const struct bench_suite *suite, 38019ea8026Sopenharmony_ci const struct bench_case *case_, 38119ea8026Sopenharmony_ci size_t perm) { 38219ea8026Sopenharmony_ci if (case_->defines) { 38319ea8026Sopenharmony_ci bench_define_maps[BENCH_DEFINE_MAP_PERMUTATION] = (bench_define_map_t){ 38419ea8026Sopenharmony_ci case_->defines + perm*suite->define_count, 38519ea8026Sopenharmony_ci suite->define_count}; 38619ea8026Sopenharmony_ci } else { 38719ea8026Sopenharmony_ci bench_define_maps[BENCH_DEFINE_MAP_PERMUTATION] = (bench_define_map_t){ 38819ea8026Sopenharmony_ci NULL, 0}; 38919ea8026Sopenharmony_ci } 39019ea8026Sopenharmony_ci} 39119ea8026Sopenharmony_ci 39219ea8026Sopenharmony_civoid bench_define_override(size_t perm) { 39319ea8026Sopenharmony_ci bench_define_maps[BENCH_DEFINE_MAP_OVERRIDE] = (bench_define_map_t){ 39419ea8026Sopenharmony_ci bench_override_defines + perm*bench_override_define_count, 39519ea8026Sopenharmony_ci bench_override_define_count}; 39619ea8026Sopenharmony_ci} 39719ea8026Sopenharmony_ci 39819ea8026Sopenharmony_civoid bench_define_explicit( 39919ea8026Sopenharmony_ci const bench_define_t *defines, 40019ea8026Sopenharmony_ci size_t define_count) { 40119ea8026Sopenharmony_ci bench_define_maps[BENCH_DEFINE_MAP_EXPLICIT] = (bench_define_map_t){ 40219ea8026Sopenharmony_ci defines, define_count}; 40319ea8026Sopenharmony_ci} 40419ea8026Sopenharmony_ci 40519ea8026Sopenharmony_civoid bench_define_cleanup(void) { 40619ea8026Sopenharmony_ci // bench define management can allocate a few things 40719ea8026Sopenharmony_ci free(bench_define_cache); 40819ea8026Sopenharmony_ci free(bench_define_cache_mask); 40919ea8026Sopenharmony_ci free(bench_override_defines); 41019ea8026Sopenharmony_ci} 41119ea8026Sopenharmony_ci 41219ea8026Sopenharmony_ci 41319ea8026Sopenharmony_ci 41419ea8026Sopenharmony_ci// bench state 41519ea8026Sopenharmony_ciextern const bench_geometry_t *bench_geometries; 41619ea8026Sopenharmony_ciextern size_t bench_geometry_count; 41719ea8026Sopenharmony_ci 41819ea8026Sopenharmony_ciconst bench_id_t *bench_ids = (const bench_id_t[]) { 41919ea8026Sopenharmony_ci {NULL, NULL, 0}, 42019ea8026Sopenharmony_ci}; 42119ea8026Sopenharmony_cisize_t bench_id_count = 1; 42219ea8026Sopenharmony_ci 42319ea8026Sopenharmony_cisize_t bench_step_start = 0; 42419ea8026Sopenharmony_cisize_t bench_step_stop = -1; 42519ea8026Sopenharmony_cisize_t bench_step_step = 1; 42619ea8026Sopenharmony_ci 42719ea8026Sopenharmony_ciconst char *bench_disk_path = NULL; 42819ea8026Sopenharmony_ciconst char *bench_trace_path = NULL; 42919ea8026Sopenharmony_cibool bench_trace_backtrace = false; 43019ea8026Sopenharmony_ciuint32_t bench_trace_period = 0; 43119ea8026Sopenharmony_ciuint32_t bench_trace_freq = 0; 43219ea8026Sopenharmony_ciFILE *bench_trace_file = NULL; 43319ea8026Sopenharmony_ciuint32_t bench_trace_cycles = 0; 43419ea8026Sopenharmony_ciuint64_t bench_trace_time = 0; 43519ea8026Sopenharmony_ciuint64_t bench_trace_open_time = 0; 43619ea8026Sopenharmony_cilfs_emubd_sleep_t bench_read_sleep = 0.0; 43719ea8026Sopenharmony_cilfs_emubd_sleep_t bench_prog_sleep = 0.0; 43819ea8026Sopenharmony_cilfs_emubd_sleep_t bench_erase_sleep = 0.0; 43919ea8026Sopenharmony_ci 44019ea8026Sopenharmony_ci// this determines both the backtrace buffer and the trace printf buffer, if 44119ea8026Sopenharmony_ci// trace ends up interleaved or truncated this may need to be increased 44219ea8026Sopenharmony_ci#ifndef BENCH_TRACE_BACKTRACE_BUFFER_SIZE 44319ea8026Sopenharmony_ci#define BENCH_TRACE_BACKTRACE_BUFFER_SIZE 8192 44419ea8026Sopenharmony_ci#endif 44519ea8026Sopenharmony_civoid *bench_trace_backtrace_buffer[ 44619ea8026Sopenharmony_ci BENCH_TRACE_BACKTRACE_BUFFER_SIZE / sizeof(void*)]; 44719ea8026Sopenharmony_ci 44819ea8026Sopenharmony_ci// trace printing 44919ea8026Sopenharmony_civoid bench_trace(const char *fmt, ...) { 45019ea8026Sopenharmony_ci if (bench_trace_path) { 45119ea8026Sopenharmony_ci // sample at a specific period? 45219ea8026Sopenharmony_ci if (bench_trace_period) { 45319ea8026Sopenharmony_ci if (bench_trace_cycles % bench_trace_period != 0) { 45419ea8026Sopenharmony_ci bench_trace_cycles += 1; 45519ea8026Sopenharmony_ci return; 45619ea8026Sopenharmony_ci } 45719ea8026Sopenharmony_ci bench_trace_cycles += 1; 45819ea8026Sopenharmony_ci } 45919ea8026Sopenharmony_ci 46019ea8026Sopenharmony_ci // sample at a specific frequency? 46119ea8026Sopenharmony_ci if (bench_trace_freq) { 46219ea8026Sopenharmony_ci struct timespec t; 46319ea8026Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &t); 46419ea8026Sopenharmony_ci uint64_t now = (uint64_t)t.tv_sec*1000*1000*1000 46519ea8026Sopenharmony_ci + (uint64_t)t.tv_nsec; 46619ea8026Sopenharmony_ci if (now - bench_trace_time < (1000*1000*1000) / bench_trace_freq) { 46719ea8026Sopenharmony_ci return; 46819ea8026Sopenharmony_ci } 46919ea8026Sopenharmony_ci bench_trace_time = now; 47019ea8026Sopenharmony_ci } 47119ea8026Sopenharmony_ci 47219ea8026Sopenharmony_ci if (!bench_trace_file) { 47319ea8026Sopenharmony_ci // Tracing output is heavy and trying to open every trace 47419ea8026Sopenharmony_ci // call is slow, so we only try to open the trace file every 47519ea8026Sopenharmony_ci // so often. Note this doesn't affect successfully opened files 47619ea8026Sopenharmony_ci struct timespec t; 47719ea8026Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &t); 47819ea8026Sopenharmony_ci uint64_t now = (uint64_t)t.tv_sec*1000*1000*1000 47919ea8026Sopenharmony_ci + (uint64_t)t.tv_nsec; 48019ea8026Sopenharmony_ci if (now - bench_trace_open_time < 100*1000*1000) { 48119ea8026Sopenharmony_ci return; 48219ea8026Sopenharmony_ci } 48319ea8026Sopenharmony_ci bench_trace_open_time = now; 48419ea8026Sopenharmony_ci 48519ea8026Sopenharmony_ci // try to open the trace file 48619ea8026Sopenharmony_ci int fd; 48719ea8026Sopenharmony_ci if (strcmp(bench_trace_path, "-") == 0) { 48819ea8026Sopenharmony_ci fd = dup(1); 48919ea8026Sopenharmony_ci if (fd < 0) { 49019ea8026Sopenharmony_ci return; 49119ea8026Sopenharmony_ci } 49219ea8026Sopenharmony_ci } else { 49319ea8026Sopenharmony_ci fd = open( 49419ea8026Sopenharmony_ci bench_trace_path, 49519ea8026Sopenharmony_ci O_WRONLY | O_CREAT | O_APPEND | O_NONBLOCK, 49619ea8026Sopenharmony_ci 0666); 49719ea8026Sopenharmony_ci if (fd < 0) { 49819ea8026Sopenharmony_ci return; 49919ea8026Sopenharmony_ci } 50019ea8026Sopenharmony_ci int err = fcntl(fd, F_SETFL, O_WRONLY | O_CREAT | O_APPEND); 50119ea8026Sopenharmony_ci assert(!err); 50219ea8026Sopenharmony_ci } 50319ea8026Sopenharmony_ci 50419ea8026Sopenharmony_ci FILE *f = fdopen(fd, "a"); 50519ea8026Sopenharmony_ci assert(f); 50619ea8026Sopenharmony_ci int err = setvbuf(f, NULL, _IOFBF, 50719ea8026Sopenharmony_ci BENCH_TRACE_BACKTRACE_BUFFER_SIZE); 50819ea8026Sopenharmony_ci assert(!err); 50919ea8026Sopenharmony_ci bench_trace_file = f; 51019ea8026Sopenharmony_ci } 51119ea8026Sopenharmony_ci 51219ea8026Sopenharmony_ci // print trace 51319ea8026Sopenharmony_ci va_list va; 51419ea8026Sopenharmony_ci va_start(va, fmt); 51519ea8026Sopenharmony_ci int res = vfprintf(bench_trace_file, fmt, va); 51619ea8026Sopenharmony_ci va_end(va); 51719ea8026Sopenharmony_ci if (res < 0) { 51819ea8026Sopenharmony_ci fclose(bench_trace_file); 51919ea8026Sopenharmony_ci bench_trace_file = NULL; 52019ea8026Sopenharmony_ci return; 52119ea8026Sopenharmony_ci } 52219ea8026Sopenharmony_ci 52319ea8026Sopenharmony_ci if (bench_trace_backtrace) { 52419ea8026Sopenharmony_ci // print backtrace 52519ea8026Sopenharmony_ci size_t count = backtrace( 52619ea8026Sopenharmony_ci bench_trace_backtrace_buffer, 52719ea8026Sopenharmony_ci BENCH_TRACE_BACKTRACE_BUFFER_SIZE); 52819ea8026Sopenharmony_ci // note we skip our own stack frame 52919ea8026Sopenharmony_ci for (size_t i = 1; i < count; i++) { 53019ea8026Sopenharmony_ci res = fprintf(bench_trace_file, "\tat %p\n", 53119ea8026Sopenharmony_ci bench_trace_backtrace_buffer[i]); 53219ea8026Sopenharmony_ci if (res < 0) { 53319ea8026Sopenharmony_ci fclose(bench_trace_file); 53419ea8026Sopenharmony_ci bench_trace_file = NULL; 53519ea8026Sopenharmony_ci return; 53619ea8026Sopenharmony_ci } 53719ea8026Sopenharmony_ci } 53819ea8026Sopenharmony_ci } 53919ea8026Sopenharmony_ci 54019ea8026Sopenharmony_ci // flush immediately 54119ea8026Sopenharmony_ci fflush(bench_trace_file); 54219ea8026Sopenharmony_ci } 54319ea8026Sopenharmony_ci} 54419ea8026Sopenharmony_ci 54519ea8026Sopenharmony_ci 54619ea8026Sopenharmony_ci// bench prng 54719ea8026Sopenharmony_ciuint32_t bench_prng(uint32_t *state) { 54819ea8026Sopenharmony_ci // A simple xorshift32 generator, easily reproducible. Keep in mind 54919ea8026Sopenharmony_ci // determinism is much more important than actual randomness here. 55019ea8026Sopenharmony_ci uint32_t x = *state; 55119ea8026Sopenharmony_ci x ^= x << 13; 55219ea8026Sopenharmony_ci x ^= x >> 17; 55319ea8026Sopenharmony_ci x ^= x << 5; 55419ea8026Sopenharmony_ci *state = x; 55519ea8026Sopenharmony_ci return x; 55619ea8026Sopenharmony_ci} 55719ea8026Sopenharmony_ci 55819ea8026Sopenharmony_ci 55919ea8026Sopenharmony_ci// bench recording state 56019ea8026Sopenharmony_cistatic struct lfs_config *bench_cfg = NULL; 56119ea8026Sopenharmony_cistatic lfs_emubd_io_t bench_last_readed = 0; 56219ea8026Sopenharmony_cistatic lfs_emubd_io_t bench_last_proged = 0; 56319ea8026Sopenharmony_cistatic lfs_emubd_io_t bench_last_erased = 0; 56419ea8026Sopenharmony_cilfs_emubd_io_t bench_readed = 0; 56519ea8026Sopenharmony_cilfs_emubd_io_t bench_proged = 0; 56619ea8026Sopenharmony_cilfs_emubd_io_t bench_erased = 0; 56719ea8026Sopenharmony_ci 56819ea8026Sopenharmony_civoid bench_reset(void) { 56919ea8026Sopenharmony_ci bench_readed = 0; 57019ea8026Sopenharmony_ci bench_proged = 0; 57119ea8026Sopenharmony_ci bench_erased = 0; 57219ea8026Sopenharmony_ci bench_last_readed = 0; 57319ea8026Sopenharmony_ci bench_last_proged = 0; 57419ea8026Sopenharmony_ci bench_last_erased = 0; 57519ea8026Sopenharmony_ci} 57619ea8026Sopenharmony_ci 57719ea8026Sopenharmony_civoid bench_start(void) { 57819ea8026Sopenharmony_ci assert(bench_cfg); 57919ea8026Sopenharmony_ci lfs_emubd_sio_t readed = lfs_emubd_readed(bench_cfg); 58019ea8026Sopenharmony_ci assert(readed >= 0); 58119ea8026Sopenharmony_ci lfs_emubd_sio_t proged = lfs_emubd_proged(bench_cfg); 58219ea8026Sopenharmony_ci assert(proged >= 0); 58319ea8026Sopenharmony_ci lfs_emubd_sio_t erased = lfs_emubd_erased(bench_cfg); 58419ea8026Sopenharmony_ci assert(erased >= 0); 58519ea8026Sopenharmony_ci 58619ea8026Sopenharmony_ci bench_last_readed = readed; 58719ea8026Sopenharmony_ci bench_last_proged = proged; 58819ea8026Sopenharmony_ci bench_last_erased = erased; 58919ea8026Sopenharmony_ci} 59019ea8026Sopenharmony_ci 59119ea8026Sopenharmony_civoid bench_stop(void) { 59219ea8026Sopenharmony_ci assert(bench_cfg); 59319ea8026Sopenharmony_ci lfs_emubd_sio_t readed = lfs_emubd_readed(bench_cfg); 59419ea8026Sopenharmony_ci assert(readed >= 0); 59519ea8026Sopenharmony_ci lfs_emubd_sio_t proged = lfs_emubd_proged(bench_cfg); 59619ea8026Sopenharmony_ci assert(proged >= 0); 59719ea8026Sopenharmony_ci lfs_emubd_sio_t erased = lfs_emubd_erased(bench_cfg); 59819ea8026Sopenharmony_ci assert(erased >= 0); 59919ea8026Sopenharmony_ci 60019ea8026Sopenharmony_ci bench_readed += readed - bench_last_readed; 60119ea8026Sopenharmony_ci bench_proged += proged - bench_last_proged; 60219ea8026Sopenharmony_ci bench_erased += erased - bench_last_erased; 60319ea8026Sopenharmony_ci} 60419ea8026Sopenharmony_ci 60519ea8026Sopenharmony_ci 60619ea8026Sopenharmony_ci// encode our permutation into a reusable id 60719ea8026Sopenharmony_cistatic void perm_printid( 60819ea8026Sopenharmony_ci const struct bench_suite *suite, 60919ea8026Sopenharmony_ci const struct bench_case *case_) { 61019ea8026Sopenharmony_ci (void)suite; 61119ea8026Sopenharmony_ci // case[:permutation] 61219ea8026Sopenharmony_ci printf("%s:", case_->name); 61319ea8026Sopenharmony_ci for (size_t d = 0; 61419ea8026Sopenharmony_ci d < lfs_max( 61519ea8026Sopenharmony_ci suite->define_count, 61619ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT); 61719ea8026Sopenharmony_ci d++) { 61819ea8026Sopenharmony_ci if (bench_define_ispermutation(d)) { 61919ea8026Sopenharmony_ci leb16_print(d); 62019ea8026Sopenharmony_ci leb16_print(BENCH_DEFINE(d)); 62119ea8026Sopenharmony_ci } 62219ea8026Sopenharmony_ci } 62319ea8026Sopenharmony_ci} 62419ea8026Sopenharmony_ci 62519ea8026Sopenharmony_ci// a quick trie for keeping track of permutations we've seen 62619ea8026Sopenharmony_citypedef struct bench_seen { 62719ea8026Sopenharmony_ci struct bench_seen_branch *branches; 62819ea8026Sopenharmony_ci size_t branch_count; 62919ea8026Sopenharmony_ci size_t branch_capacity; 63019ea8026Sopenharmony_ci} bench_seen_t; 63119ea8026Sopenharmony_ci 63219ea8026Sopenharmony_cistruct bench_seen_branch { 63319ea8026Sopenharmony_ci intmax_t define; 63419ea8026Sopenharmony_ci struct bench_seen branch; 63519ea8026Sopenharmony_ci}; 63619ea8026Sopenharmony_ci 63719ea8026Sopenharmony_cibool bench_seen_insert( 63819ea8026Sopenharmony_ci bench_seen_t *seen, 63919ea8026Sopenharmony_ci const struct bench_suite *suite, 64019ea8026Sopenharmony_ci const struct bench_case *case_) { 64119ea8026Sopenharmony_ci (void)case_; 64219ea8026Sopenharmony_ci bool was_seen = true; 64319ea8026Sopenharmony_ci 64419ea8026Sopenharmony_ci // use the currently set defines 64519ea8026Sopenharmony_ci for (size_t d = 0; 64619ea8026Sopenharmony_ci d < lfs_max( 64719ea8026Sopenharmony_ci suite->define_count, 64819ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT); 64919ea8026Sopenharmony_ci d++) { 65019ea8026Sopenharmony_ci // treat unpermuted defines the same as 0 65119ea8026Sopenharmony_ci intmax_t define = bench_define_ispermutation(d) ? BENCH_DEFINE(d) : 0; 65219ea8026Sopenharmony_ci 65319ea8026Sopenharmony_ci // already seen? 65419ea8026Sopenharmony_ci struct bench_seen_branch *branch = NULL; 65519ea8026Sopenharmony_ci for (size_t i = 0; i < seen->branch_count; i++) { 65619ea8026Sopenharmony_ci if (seen->branches[i].define == define) { 65719ea8026Sopenharmony_ci branch = &seen->branches[i]; 65819ea8026Sopenharmony_ci break; 65919ea8026Sopenharmony_ci } 66019ea8026Sopenharmony_ci } 66119ea8026Sopenharmony_ci 66219ea8026Sopenharmony_ci // need to create a new node 66319ea8026Sopenharmony_ci if (!branch) { 66419ea8026Sopenharmony_ci was_seen = false; 66519ea8026Sopenharmony_ci branch = mappend( 66619ea8026Sopenharmony_ci (void**)&seen->branches, 66719ea8026Sopenharmony_ci sizeof(struct bench_seen_branch), 66819ea8026Sopenharmony_ci &seen->branch_count, 66919ea8026Sopenharmony_ci &seen->branch_capacity); 67019ea8026Sopenharmony_ci branch->define = define; 67119ea8026Sopenharmony_ci branch->branch = (bench_seen_t){NULL, 0, 0}; 67219ea8026Sopenharmony_ci } 67319ea8026Sopenharmony_ci 67419ea8026Sopenharmony_ci seen = &branch->branch; 67519ea8026Sopenharmony_ci } 67619ea8026Sopenharmony_ci 67719ea8026Sopenharmony_ci return was_seen; 67819ea8026Sopenharmony_ci} 67919ea8026Sopenharmony_ci 68019ea8026Sopenharmony_civoid bench_seen_cleanup(bench_seen_t *seen) { 68119ea8026Sopenharmony_ci for (size_t i = 0; i < seen->branch_count; i++) { 68219ea8026Sopenharmony_ci bench_seen_cleanup(&seen->branches[i].branch); 68319ea8026Sopenharmony_ci } 68419ea8026Sopenharmony_ci free(seen->branches); 68519ea8026Sopenharmony_ci} 68619ea8026Sopenharmony_ci 68719ea8026Sopenharmony_ci// iterate through permutations in a bench case 68819ea8026Sopenharmony_cistatic void case_forperm( 68919ea8026Sopenharmony_ci const struct bench_suite *suite, 69019ea8026Sopenharmony_ci const struct bench_case *case_, 69119ea8026Sopenharmony_ci const bench_define_t *defines, 69219ea8026Sopenharmony_ci size_t define_count, 69319ea8026Sopenharmony_ci void (*cb)( 69419ea8026Sopenharmony_ci void *data, 69519ea8026Sopenharmony_ci const struct bench_suite *suite, 69619ea8026Sopenharmony_ci const struct bench_case *case_), 69719ea8026Sopenharmony_ci void *data) { 69819ea8026Sopenharmony_ci // explicit permutation? 69919ea8026Sopenharmony_ci if (defines) { 70019ea8026Sopenharmony_ci bench_define_explicit(defines, define_count); 70119ea8026Sopenharmony_ci 70219ea8026Sopenharmony_ci for (size_t v = 0; v < bench_override_define_permutations; v++) { 70319ea8026Sopenharmony_ci // define override permutation 70419ea8026Sopenharmony_ci bench_define_override(v); 70519ea8026Sopenharmony_ci bench_define_flush(); 70619ea8026Sopenharmony_ci 70719ea8026Sopenharmony_ci cb(data, suite, case_); 70819ea8026Sopenharmony_ci } 70919ea8026Sopenharmony_ci 71019ea8026Sopenharmony_ci return; 71119ea8026Sopenharmony_ci } 71219ea8026Sopenharmony_ci 71319ea8026Sopenharmony_ci bench_seen_t seen = {NULL, 0, 0}; 71419ea8026Sopenharmony_ci 71519ea8026Sopenharmony_ci for (size_t k = 0; k < case_->permutations; k++) { 71619ea8026Sopenharmony_ci // define permutation 71719ea8026Sopenharmony_ci bench_define_perm(suite, case_, k); 71819ea8026Sopenharmony_ci 71919ea8026Sopenharmony_ci for (size_t v = 0; v < bench_override_define_permutations; v++) { 72019ea8026Sopenharmony_ci // define override permutation 72119ea8026Sopenharmony_ci bench_define_override(v); 72219ea8026Sopenharmony_ci 72319ea8026Sopenharmony_ci for (size_t g = 0; g < bench_geometry_count; g++) { 72419ea8026Sopenharmony_ci // define geometry 72519ea8026Sopenharmony_ci bench_define_geometry(&bench_geometries[g]); 72619ea8026Sopenharmony_ci bench_define_flush(); 72719ea8026Sopenharmony_ci 72819ea8026Sopenharmony_ci // have we seen this permutation before? 72919ea8026Sopenharmony_ci bool was_seen = bench_seen_insert(&seen, suite, case_); 73019ea8026Sopenharmony_ci if (!(k == 0 && v == 0 && g == 0) && was_seen) { 73119ea8026Sopenharmony_ci continue; 73219ea8026Sopenharmony_ci } 73319ea8026Sopenharmony_ci 73419ea8026Sopenharmony_ci cb(data, suite, case_); 73519ea8026Sopenharmony_ci } 73619ea8026Sopenharmony_ci } 73719ea8026Sopenharmony_ci } 73819ea8026Sopenharmony_ci 73919ea8026Sopenharmony_ci bench_seen_cleanup(&seen); 74019ea8026Sopenharmony_ci} 74119ea8026Sopenharmony_ci 74219ea8026Sopenharmony_ci 74319ea8026Sopenharmony_ci// how many permutations are there actually in a bench case 74419ea8026Sopenharmony_cistruct perm_count_state { 74519ea8026Sopenharmony_ci size_t total; 74619ea8026Sopenharmony_ci size_t filtered; 74719ea8026Sopenharmony_ci}; 74819ea8026Sopenharmony_ci 74919ea8026Sopenharmony_civoid perm_count( 75019ea8026Sopenharmony_ci void *data, 75119ea8026Sopenharmony_ci const struct bench_suite *suite, 75219ea8026Sopenharmony_ci const struct bench_case *case_) { 75319ea8026Sopenharmony_ci struct perm_count_state *state = data; 75419ea8026Sopenharmony_ci (void)suite; 75519ea8026Sopenharmony_ci (void)case_; 75619ea8026Sopenharmony_ci 75719ea8026Sopenharmony_ci state->total += 1; 75819ea8026Sopenharmony_ci 75919ea8026Sopenharmony_ci if (case_->filter && !case_->filter()) { 76019ea8026Sopenharmony_ci return; 76119ea8026Sopenharmony_ci } 76219ea8026Sopenharmony_ci 76319ea8026Sopenharmony_ci state->filtered += 1; 76419ea8026Sopenharmony_ci} 76519ea8026Sopenharmony_ci 76619ea8026Sopenharmony_ci 76719ea8026Sopenharmony_ci// operations we can do 76819ea8026Sopenharmony_cistatic void summary(void) { 76919ea8026Sopenharmony_ci printf("%-23s %7s %7s %7s %11s\n", 77019ea8026Sopenharmony_ci "", "flags", "suites", "cases", "perms"); 77119ea8026Sopenharmony_ci size_t suites = 0; 77219ea8026Sopenharmony_ci size_t cases = 0; 77319ea8026Sopenharmony_ci bench_flags_t flags = 0; 77419ea8026Sopenharmony_ci struct perm_count_state perms = {0, 0}; 77519ea8026Sopenharmony_ci 77619ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 77719ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 77819ea8026Sopenharmony_ci bench_define_suite(&bench_suites[i]); 77919ea8026Sopenharmony_ci 78019ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 78119ea8026Sopenharmony_ci // does neither suite nor case name match? 78219ea8026Sopenharmony_ci if (bench_ids[t].name && !( 78319ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 78419ea8026Sopenharmony_ci bench_suites[i].name) == 0 78519ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 78619ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 78719ea8026Sopenharmony_ci continue; 78819ea8026Sopenharmony_ci } 78919ea8026Sopenharmony_ci 79019ea8026Sopenharmony_ci cases += 1; 79119ea8026Sopenharmony_ci case_forperm( 79219ea8026Sopenharmony_ci &bench_suites[i], 79319ea8026Sopenharmony_ci &bench_suites[i].cases[j], 79419ea8026Sopenharmony_ci bench_ids[t].defines, 79519ea8026Sopenharmony_ci bench_ids[t].define_count, 79619ea8026Sopenharmony_ci perm_count, 79719ea8026Sopenharmony_ci &perms); 79819ea8026Sopenharmony_ci } 79919ea8026Sopenharmony_ci 80019ea8026Sopenharmony_ci suites += 1; 80119ea8026Sopenharmony_ci flags |= bench_suites[i].flags; 80219ea8026Sopenharmony_ci } 80319ea8026Sopenharmony_ci } 80419ea8026Sopenharmony_ci 80519ea8026Sopenharmony_ci char perm_buf[64]; 80619ea8026Sopenharmony_ci sprintf(perm_buf, "%zu/%zu", perms.filtered, perms.total); 80719ea8026Sopenharmony_ci char flag_buf[64]; 80819ea8026Sopenharmony_ci sprintf(flag_buf, "%s%s", 80919ea8026Sopenharmony_ci (flags & BENCH_REENTRANT) ? "r" : "", 81019ea8026Sopenharmony_ci (!flags) ? "-" : ""); 81119ea8026Sopenharmony_ci printf("%-23s %7s %7zu %7zu %11s\n", 81219ea8026Sopenharmony_ci "TOTAL", 81319ea8026Sopenharmony_ci flag_buf, 81419ea8026Sopenharmony_ci suites, 81519ea8026Sopenharmony_ci cases, 81619ea8026Sopenharmony_ci perm_buf); 81719ea8026Sopenharmony_ci} 81819ea8026Sopenharmony_ci 81919ea8026Sopenharmony_cistatic void list_suites(void) { 82019ea8026Sopenharmony_ci // at least size so that names fit 82119ea8026Sopenharmony_ci unsigned name_width = 23; 82219ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 82319ea8026Sopenharmony_ci size_t len = strlen(bench_suites[i].name); 82419ea8026Sopenharmony_ci if (len > name_width) { 82519ea8026Sopenharmony_ci name_width = len; 82619ea8026Sopenharmony_ci } 82719ea8026Sopenharmony_ci } 82819ea8026Sopenharmony_ci name_width = 4*((name_width+1+4-1)/4)-1; 82919ea8026Sopenharmony_ci 83019ea8026Sopenharmony_ci printf("%-*s %7s %7s %11s\n", 83119ea8026Sopenharmony_ci name_width, "suite", "flags", "cases", "perms"); 83219ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 83319ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 83419ea8026Sopenharmony_ci bench_define_suite(&bench_suites[i]); 83519ea8026Sopenharmony_ci 83619ea8026Sopenharmony_ci size_t cases = 0; 83719ea8026Sopenharmony_ci struct perm_count_state perms = {0, 0}; 83819ea8026Sopenharmony_ci 83919ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 84019ea8026Sopenharmony_ci // does neither suite nor case name match? 84119ea8026Sopenharmony_ci if (bench_ids[t].name && !( 84219ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 84319ea8026Sopenharmony_ci bench_suites[i].name) == 0 84419ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 84519ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 84619ea8026Sopenharmony_ci continue; 84719ea8026Sopenharmony_ci } 84819ea8026Sopenharmony_ci 84919ea8026Sopenharmony_ci cases += 1; 85019ea8026Sopenharmony_ci case_forperm( 85119ea8026Sopenharmony_ci &bench_suites[i], 85219ea8026Sopenharmony_ci &bench_suites[i].cases[j], 85319ea8026Sopenharmony_ci bench_ids[t].defines, 85419ea8026Sopenharmony_ci bench_ids[t].define_count, 85519ea8026Sopenharmony_ci perm_count, 85619ea8026Sopenharmony_ci &perms); 85719ea8026Sopenharmony_ci } 85819ea8026Sopenharmony_ci 85919ea8026Sopenharmony_ci // no benches found? 86019ea8026Sopenharmony_ci if (!cases) { 86119ea8026Sopenharmony_ci continue; 86219ea8026Sopenharmony_ci } 86319ea8026Sopenharmony_ci 86419ea8026Sopenharmony_ci char perm_buf[64]; 86519ea8026Sopenharmony_ci sprintf(perm_buf, "%zu/%zu", perms.filtered, perms.total); 86619ea8026Sopenharmony_ci char flag_buf[64]; 86719ea8026Sopenharmony_ci sprintf(flag_buf, "%s%s", 86819ea8026Sopenharmony_ci (bench_suites[i].flags & BENCH_REENTRANT) ? "r" : "", 86919ea8026Sopenharmony_ci (!bench_suites[i].flags) ? "-" : ""); 87019ea8026Sopenharmony_ci printf("%-*s %7s %7zu %11s\n", 87119ea8026Sopenharmony_ci name_width, 87219ea8026Sopenharmony_ci bench_suites[i].name, 87319ea8026Sopenharmony_ci flag_buf, 87419ea8026Sopenharmony_ci cases, 87519ea8026Sopenharmony_ci perm_buf); 87619ea8026Sopenharmony_ci } 87719ea8026Sopenharmony_ci } 87819ea8026Sopenharmony_ci} 87919ea8026Sopenharmony_ci 88019ea8026Sopenharmony_cistatic void list_cases(void) { 88119ea8026Sopenharmony_ci // at least size so that names fit 88219ea8026Sopenharmony_ci unsigned name_width = 23; 88319ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 88419ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 88519ea8026Sopenharmony_ci size_t len = strlen(bench_suites[i].cases[j].name); 88619ea8026Sopenharmony_ci if (len > name_width) { 88719ea8026Sopenharmony_ci name_width = len; 88819ea8026Sopenharmony_ci } 88919ea8026Sopenharmony_ci } 89019ea8026Sopenharmony_ci } 89119ea8026Sopenharmony_ci name_width = 4*((name_width+1+4-1)/4)-1; 89219ea8026Sopenharmony_ci 89319ea8026Sopenharmony_ci printf("%-*s %7s %11s\n", name_width, "case", "flags", "perms"); 89419ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 89519ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 89619ea8026Sopenharmony_ci bench_define_suite(&bench_suites[i]); 89719ea8026Sopenharmony_ci 89819ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 89919ea8026Sopenharmony_ci // does neither suite nor case name match? 90019ea8026Sopenharmony_ci if (bench_ids[t].name && !( 90119ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 90219ea8026Sopenharmony_ci bench_suites[i].name) == 0 90319ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 90419ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 90519ea8026Sopenharmony_ci continue; 90619ea8026Sopenharmony_ci } 90719ea8026Sopenharmony_ci 90819ea8026Sopenharmony_ci struct perm_count_state perms = {0, 0}; 90919ea8026Sopenharmony_ci case_forperm( 91019ea8026Sopenharmony_ci &bench_suites[i], 91119ea8026Sopenharmony_ci &bench_suites[i].cases[j], 91219ea8026Sopenharmony_ci bench_ids[t].defines, 91319ea8026Sopenharmony_ci bench_ids[t].define_count, 91419ea8026Sopenharmony_ci perm_count, 91519ea8026Sopenharmony_ci &perms); 91619ea8026Sopenharmony_ci 91719ea8026Sopenharmony_ci char perm_buf[64]; 91819ea8026Sopenharmony_ci sprintf(perm_buf, "%zu/%zu", perms.filtered, perms.total); 91919ea8026Sopenharmony_ci char flag_buf[64]; 92019ea8026Sopenharmony_ci sprintf(flag_buf, "%s%s", 92119ea8026Sopenharmony_ci (bench_suites[i].cases[j].flags & BENCH_REENTRANT) 92219ea8026Sopenharmony_ci ? "r" : "", 92319ea8026Sopenharmony_ci (!bench_suites[i].cases[j].flags) 92419ea8026Sopenharmony_ci ? "-" : ""); 92519ea8026Sopenharmony_ci printf("%-*s %7s %11s\n", 92619ea8026Sopenharmony_ci name_width, 92719ea8026Sopenharmony_ci bench_suites[i].cases[j].name, 92819ea8026Sopenharmony_ci flag_buf, 92919ea8026Sopenharmony_ci perm_buf); 93019ea8026Sopenharmony_ci } 93119ea8026Sopenharmony_ci } 93219ea8026Sopenharmony_ci } 93319ea8026Sopenharmony_ci} 93419ea8026Sopenharmony_ci 93519ea8026Sopenharmony_cistatic void list_suite_paths(void) { 93619ea8026Sopenharmony_ci // at least size so that names fit 93719ea8026Sopenharmony_ci unsigned name_width = 23; 93819ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 93919ea8026Sopenharmony_ci size_t len = strlen(bench_suites[i].name); 94019ea8026Sopenharmony_ci if (len > name_width) { 94119ea8026Sopenharmony_ci name_width = len; 94219ea8026Sopenharmony_ci } 94319ea8026Sopenharmony_ci } 94419ea8026Sopenharmony_ci name_width = 4*((name_width+1+4-1)/4)-1; 94519ea8026Sopenharmony_ci 94619ea8026Sopenharmony_ci printf("%-*s %s\n", name_width, "suite", "path"); 94719ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 94819ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 94919ea8026Sopenharmony_ci size_t cases = 0; 95019ea8026Sopenharmony_ci 95119ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 95219ea8026Sopenharmony_ci // does neither suite nor case name match? 95319ea8026Sopenharmony_ci if (bench_ids[t].name && !( 95419ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 95519ea8026Sopenharmony_ci bench_suites[i].name) == 0 95619ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 95719ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 95819ea8026Sopenharmony_ci continue; 95919ea8026Sopenharmony_ci 96019ea8026Sopenharmony_ci cases += 1; 96119ea8026Sopenharmony_ci } 96219ea8026Sopenharmony_ci } 96319ea8026Sopenharmony_ci 96419ea8026Sopenharmony_ci // no benches found? 96519ea8026Sopenharmony_ci if (!cases) { 96619ea8026Sopenharmony_ci continue; 96719ea8026Sopenharmony_ci } 96819ea8026Sopenharmony_ci 96919ea8026Sopenharmony_ci printf("%-*s %s\n", 97019ea8026Sopenharmony_ci name_width, 97119ea8026Sopenharmony_ci bench_suites[i].name, 97219ea8026Sopenharmony_ci bench_suites[i].path); 97319ea8026Sopenharmony_ci } 97419ea8026Sopenharmony_ci } 97519ea8026Sopenharmony_ci} 97619ea8026Sopenharmony_ci 97719ea8026Sopenharmony_cistatic void list_case_paths(void) { 97819ea8026Sopenharmony_ci // at least size so that names fit 97919ea8026Sopenharmony_ci unsigned name_width = 23; 98019ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 98119ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 98219ea8026Sopenharmony_ci size_t len = strlen(bench_suites[i].cases[j].name); 98319ea8026Sopenharmony_ci if (len > name_width) { 98419ea8026Sopenharmony_ci name_width = len; 98519ea8026Sopenharmony_ci } 98619ea8026Sopenharmony_ci } 98719ea8026Sopenharmony_ci } 98819ea8026Sopenharmony_ci name_width = 4*((name_width+1+4-1)/4)-1; 98919ea8026Sopenharmony_ci 99019ea8026Sopenharmony_ci printf("%-*s %s\n", name_width, "case", "path"); 99119ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 99219ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 99319ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 99419ea8026Sopenharmony_ci // does neither suite nor case name match? 99519ea8026Sopenharmony_ci if (bench_ids[t].name && !( 99619ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 99719ea8026Sopenharmony_ci bench_suites[i].name) == 0 99819ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 99919ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 100019ea8026Sopenharmony_ci continue; 100119ea8026Sopenharmony_ci } 100219ea8026Sopenharmony_ci 100319ea8026Sopenharmony_ci printf("%-*s %s\n", 100419ea8026Sopenharmony_ci name_width, 100519ea8026Sopenharmony_ci bench_suites[i].cases[j].name, 100619ea8026Sopenharmony_ci bench_suites[i].cases[j].path); 100719ea8026Sopenharmony_ci } 100819ea8026Sopenharmony_ci } 100919ea8026Sopenharmony_ci } 101019ea8026Sopenharmony_ci} 101119ea8026Sopenharmony_ci 101219ea8026Sopenharmony_cistruct list_defines_define { 101319ea8026Sopenharmony_ci const char *name; 101419ea8026Sopenharmony_ci intmax_t *values; 101519ea8026Sopenharmony_ci size_t value_count; 101619ea8026Sopenharmony_ci size_t value_capacity; 101719ea8026Sopenharmony_ci}; 101819ea8026Sopenharmony_ci 101919ea8026Sopenharmony_cistruct list_defines_defines { 102019ea8026Sopenharmony_ci struct list_defines_define *defines; 102119ea8026Sopenharmony_ci size_t define_count; 102219ea8026Sopenharmony_ci size_t define_capacity; 102319ea8026Sopenharmony_ci}; 102419ea8026Sopenharmony_ci 102519ea8026Sopenharmony_cistatic void list_defines_add( 102619ea8026Sopenharmony_ci struct list_defines_defines *defines, 102719ea8026Sopenharmony_ci size_t d) { 102819ea8026Sopenharmony_ci const char *name = bench_define_name(d); 102919ea8026Sopenharmony_ci intmax_t value = BENCH_DEFINE(d); 103019ea8026Sopenharmony_ci 103119ea8026Sopenharmony_ci // define already in defines? 103219ea8026Sopenharmony_ci for (size_t i = 0; i < defines->define_count; i++) { 103319ea8026Sopenharmony_ci if (strcmp(defines->defines[i].name, name) == 0) { 103419ea8026Sopenharmony_ci // value already in values? 103519ea8026Sopenharmony_ci for (size_t j = 0; j < defines->defines[i].value_count; j++) { 103619ea8026Sopenharmony_ci if (defines->defines[i].values[j] == value) { 103719ea8026Sopenharmony_ci return; 103819ea8026Sopenharmony_ci } 103919ea8026Sopenharmony_ci } 104019ea8026Sopenharmony_ci 104119ea8026Sopenharmony_ci *(intmax_t*)mappend( 104219ea8026Sopenharmony_ci (void**)&defines->defines[i].values, 104319ea8026Sopenharmony_ci sizeof(intmax_t), 104419ea8026Sopenharmony_ci &defines->defines[i].value_count, 104519ea8026Sopenharmony_ci &defines->defines[i].value_capacity) = value; 104619ea8026Sopenharmony_ci 104719ea8026Sopenharmony_ci return; 104819ea8026Sopenharmony_ci } 104919ea8026Sopenharmony_ci } 105019ea8026Sopenharmony_ci 105119ea8026Sopenharmony_ci // new define? 105219ea8026Sopenharmony_ci struct list_defines_define *define = mappend( 105319ea8026Sopenharmony_ci (void**)&defines->defines, 105419ea8026Sopenharmony_ci sizeof(struct list_defines_define), 105519ea8026Sopenharmony_ci &defines->define_count, 105619ea8026Sopenharmony_ci &defines->define_capacity); 105719ea8026Sopenharmony_ci define->name = name; 105819ea8026Sopenharmony_ci define->values = malloc(sizeof(intmax_t)); 105919ea8026Sopenharmony_ci define->values[0] = value; 106019ea8026Sopenharmony_ci define->value_count = 1; 106119ea8026Sopenharmony_ci define->value_capacity = 1; 106219ea8026Sopenharmony_ci} 106319ea8026Sopenharmony_ci 106419ea8026Sopenharmony_civoid perm_list_defines( 106519ea8026Sopenharmony_ci void *data, 106619ea8026Sopenharmony_ci const struct bench_suite *suite, 106719ea8026Sopenharmony_ci const struct bench_case *case_) { 106819ea8026Sopenharmony_ci struct list_defines_defines *defines = data; 106919ea8026Sopenharmony_ci (void)suite; 107019ea8026Sopenharmony_ci (void)case_; 107119ea8026Sopenharmony_ci 107219ea8026Sopenharmony_ci // collect defines 107319ea8026Sopenharmony_ci for (size_t d = 0; 107419ea8026Sopenharmony_ci d < lfs_max(suite->define_count, 107519ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT); 107619ea8026Sopenharmony_ci d++) { 107719ea8026Sopenharmony_ci if (d < BENCH_IMPLICIT_DEFINE_COUNT 107819ea8026Sopenharmony_ci || bench_define_ispermutation(d)) { 107919ea8026Sopenharmony_ci list_defines_add(defines, d); 108019ea8026Sopenharmony_ci } 108119ea8026Sopenharmony_ci } 108219ea8026Sopenharmony_ci} 108319ea8026Sopenharmony_ci 108419ea8026Sopenharmony_civoid perm_list_permutation_defines( 108519ea8026Sopenharmony_ci void *data, 108619ea8026Sopenharmony_ci const struct bench_suite *suite, 108719ea8026Sopenharmony_ci const struct bench_case *case_) { 108819ea8026Sopenharmony_ci struct list_defines_defines *defines = data; 108919ea8026Sopenharmony_ci (void)suite; 109019ea8026Sopenharmony_ci (void)case_; 109119ea8026Sopenharmony_ci 109219ea8026Sopenharmony_ci // collect permutation_defines 109319ea8026Sopenharmony_ci for (size_t d = 0; 109419ea8026Sopenharmony_ci d < lfs_max(suite->define_count, 109519ea8026Sopenharmony_ci BENCH_IMPLICIT_DEFINE_COUNT); 109619ea8026Sopenharmony_ci d++) { 109719ea8026Sopenharmony_ci if (bench_define_ispermutation(d)) { 109819ea8026Sopenharmony_ci list_defines_add(defines, d); 109919ea8026Sopenharmony_ci } 110019ea8026Sopenharmony_ci } 110119ea8026Sopenharmony_ci} 110219ea8026Sopenharmony_ci 110319ea8026Sopenharmony_ciextern const bench_geometry_t builtin_geometries[]; 110419ea8026Sopenharmony_ci 110519ea8026Sopenharmony_cistatic void list_defines(void) { 110619ea8026Sopenharmony_ci struct list_defines_defines defines = {NULL, 0, 0}; 110719ea8026Sopenharmony_ci 110819ea8026Sopenharmony_ci // add defines 110919ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 111019ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 111119ea8026Sopenharmony_ci bench_define_suite(&bench_suites[i]); 111219ea8026Sopenharmony_ci 111319ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 111419ea8026Sopenharmony_ci // does neither suite nor case name match? 111519ea8026Sopenharmony_ci if (bench_ids[t].name && !( 111619ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 111719ea8026Sopenharmony_ci bench_suites[i].name) == 0 111819ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 111919ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 112019ea8026Sopenharmony_ci continue; 112119ea8026Sopenharmony_ci } 112219ea8026Sopenharmony_ci 112319ea8026Sopenharmony_ci case_forperm( 112419ea8026Sopenharmony_ci &bench_suites[i], 112519ea8026Sopenharmony_ci &bench_suites[i].cases[j], 112619ea8026Sopenharmony_ci bench_ids[t].defines, 112719ea8026Sopenharmony_ci bench_ids[t].define_count, 112819ea8026Sopenharmony_ci perm_list_defines, 112919ea8026Sopenharmony_ci &defines); 113019ea8026Sopenharmony_ci } 113119ea8026Sopenharmony_ci } 113219ea8026Sopenharmony_ci } 113319ea8026Sopenharmony_ci 113419ea8026Sopenharmony_ci for (size_t i = 0; i < defines.define_count; i++) { 113519ea8026Sopenharmony_ci printf("%s=", defines.defines[i].name); 113619ea8026Sopenharmony_ci for (size_t j = 0; j < defines.defines[i].value_count; j++) { 113719ea8026Sopenharmony_ci printf("%jd", defines.defines[i].values[j]); 113819ea8026Sopenharmony_ci if (j != defines.defines[i].value_count-1) { 113919ea8026Sopenharmony_ci printf(","); 114019ea8026Sopenharmony_ci } 114119ea8026Sopenharmony_ci } 114219ea8026Sopenharmony_ci printf("\n"); 114319ea8026Sopenharmony_ci } 114419ea8026Sopenharmony_ci 114519ea8026Sopenharmony_ci for (size_t i = 0; i < defines.define_count; i++) { 114619ea8026Sopenharmony_ci free(defines.defines[i].values); 114719ea8026Sopenharmony_ci } 114819ea8026Sopenharmony_ci free(defines.defines); 114919ea8026Sopenharmony_ci} 115019ea8026Sopenharmony_ci 115119ea8026Sopenharmony_cistatic void list_permutation_defines(void) { 115219ea8026Sopenharmony_ci struct list_defines_defines defines = {NULL, 0, 0}; 115319ea8026Sopenharmony_ci 115419ea8026Sopenharmony_ci // add permutation defines 115519ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 115619ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 115719ea8026Sopenharmony_ci bench_define_suite(&bench_suites[i]); 115819ea8026Sopenharmony_ci 115919ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 116019ea8026Sopenharmony_ci // does neither suite nor case name match? 116119ea8026Sopenharmony_ci if (bench_ids[t].name && !( 116219ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 116319ea8026Sopenharmony_ci bench_suites[i].name) == 0 116419ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 116519ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 116619ea8026Sopenharmony_ci continue; 116719ea8026Sopenharmony_ci } 116819ea8026Sopenharmony_ci 116919ea8026Sopenharmony_ci case_forperm( 117019ea8026Sopenharmony_ci &bench_suites[i], 117119ea8026Sopenharmony_ci &bench_suites[i].cases[j], 117219ea8026Sopenharmony_ci bench_ids[t].defines, 117319ea8026Sopenharmony_ci bench_ids[t].define_count, 117419ea8026Sopenharmony_ci perm_list_permutation_defines, 117519ea8026Sopenharmony_ci &defines); 117619ea8026Sopenharmony_ci } 117719ea8026Sopenharmony_ci } 117819ea8026Sopenharmony_ci } 117919ea8026Sopenharmony_ci 118019ea8026Sopenharmony_ci for (size_t i = 0; i < defines.define_count; i++) { 118119ea8026Sopenharmony_ci printf("%s=", defines.defines[i].name); 118219ea8026Sopenharmony_ci for (size_t j = 0; j < defines.defines[i].value_count; j++) { 118319ea8026Sopenharmony_ci printf("%jd", defines.defines[i].values[j]); 118419ea8026Sopenharmony_ci if (j != defines.defines[i].value_count-1) { 118519ea8026Sopenharmony_ci printf(","); 118619ea8026Sopenharmony_ci } 118719ea8026Sopenharmony_ci } 118819ea8026Sopenharmony_ci printf("\n"); 118919ea8026Sopenharmony_ci } 119019ea8026Sopenharmony_ci 119119ea8026Sopenharmony_ci for (size_t i = 0; i < defines.define_count; i++) { 119219ea8026Sopenharmony_ci free(defines.defines[i].values); 119319ea8026Sopenharmony_ci } 119419ea8026Sopenharmony_ci free(defines.defines); 119519ea8026Sopenharmony_ci} 119619ea8026Sopenharmony_ci 119719ea8026Sopenharmony_cistatic void list_implicit_defines(void) { 119819ea8026Sopenharmony_ci struct list_defines_defines defines = {NULL, 0, 0}; 119919ea8026Sopenharmony_ci 120019ea8026Sopenharmony_ci // yes we do need to define a suite, this does a bit of bookeeping 120119ea8026Sopenharmony_ci // such as setting up the define cache 120219ea8026Sopenharmony_ci bench_define_suite(&(const struct bench_suite){0}); 120319ea8026Sopenharmony_ci 120419ea8026Sopenharmony_ci // make sure to include builtin geometries here 120519ea8026Sopenharmony_ci extern const bench_geometry_t builtin_geometries[]; 120619ea8026Sopenharmony_ci for (size_t g = 0; builtin_geometries[g].name; g++) { 120719ea8026Sopenharmony_ci bench_define_geometry(&builtin_geometries[g]); 120819ea8026Sopenharmony_ci bench_define_flush(); 120919ea8026Sopenharmony_ci 121019ea8026Sopenharmony_ci // add implicit defines 121119ea8026Sopenharmony_ci for (size_t d = 0; d < BENCH_IMPLICIT_DEFINE_COUNT; d++) { 121219ea8026Sopenharmony_ci list_defines_add(&defines, d); 121319ea8026Sopenharmony_ci } 121419ea8026Sopenharmony_ci } 121519ea8026Sopenharmony_ci 121619ea8026Sopenharmony_ci for (size_t i = 0; i < defines.define_count; i++) { 121719ea8026Sopenharmony_ci printf("%s=", defines.defines[i].name); 121819ea8026Sopenharmony_ci for (size_t j = 0; j < defines.defines[i].value_count; j++) { 121919ea8026Sopenharmony_ci printf("%jd", defines.defines[i].values[j]); 122019ea8026Sopenharmony_ci if (j != defines.defines[i].value_count-1) { 122119ea8026Sopenharmony_ci printf(","); 122219ea8026Sopenharmony_ci } 122319ea8026Sopenharmony_ci } 122419ea8026Sopenharmony_ci printf("\n"); 122519ea8026Sopenharmony_ci } 122619ea8026Sopenharmony_ci 122719ea8026Sopenharmony_ci for (size_t i = 0; i < defines.define_count; i++) { 122819ea8026Sopenharmony_ci free(defines.defines[i].values); 122919ea8026Sopenharmony_ci } 123019ea8026Sopenharmony_ci free(defines.defines); 123119ea8026Sopenharmony_ci} 123219ea8026Sopenharmony_ci 123319ea8026Sopenharmony_ci 123419ea8026Sopenharmony_ci 123519ea8026Sopenharmony_ci// geometries to bench 123619ea8026Sopenharmony_ci 123719ea8026Sopenharmony_ciconst bench_geometry_t builtin_geometries[] = { 123819ea8026Sopenharmony_ci {"default", {{0}, BENCH_CONST(16), BENCH_CONST(512), {0}}}, 123919ea8026Sopenharmony_ci {"eeprom", {{0}, BENCH_CONST(1), BENCH_CONST(512), {0}}}, 124019ea8026Sopenharmony_ci {"emmc", {{0}, {0}, BENCH_CONST(512), {0}}}, 124119ea8026Sopenharmony_ci {"nor", {{0}, BENCH_CONST(1), BENCH_CONST(4096), {0}}}, 124219ea8026Sopenharmony_ci {"nand", {{0}, BENCH_CONST(4096), BENCH_CONST(32768), {0}}}, 124319ea8026Sopenharmony_ci {NULL, {{0}, {0}, {0}, {0}}}, 124419ea8026Sopenharmony_ci}; 124519ea8026Sopenharmony_ci 124619ea8026Sopenharmony_ciconst bench_geometry_t *bench_geometries = builtin_geometries; 124719ea8026Sopenharmony_cisize_t bench_geometry_count = 5; 124819ea8026Sopenharmony_ci 124919ea8026Sopenharmony_cistatic void list_geometries(void) { 125019ea8026Sopenharmony_ci // at least size so that names fit 125119ea8026Sopenharmony_ci unsigned name_width = 23; 125219ea8026Sopenharmony_ci for (size_t g = 0; builtin_geometries[g].name; g++) { 125319ea8026Sopenharmony_ci size_t len = strlen(builtin_geometries[g].name); 125419ea8026Sopenharmony_ci if (len > name_width) { 125519ea8026Sopenharmony_ci name_width = len; 125619ea8026Sopenharmony_ci } 125719ea8026Sopenharmony_ci } 125819ea8026Sopenharmony_ci name_width = 4*((name_width+1+4-1)/4)-1; 125919ea8026Sopenharmony_ci 126019ea8026Sopenharmony_ci // yes we do need to define a suite, this does a bit of bookeeping 126119ea8026Sopenharmony_ci // such as setting up the define cache 126219ea8026Sopenharmony_ci bench_define_suite(&(const struct bench_suite){0}); 126319ea8026Sopenharmony_ci 126419ea8026Sopenharmony_ci printf("%-*s %7s %7s %7s %7s %11s\n", 126519ea8026Sopenharmony_ci name_width, "geometry", "read", "prog", "erase", "count", "size"); 126619ea8026Sopenharmony_ci for (size_t g = 0; builtin_geometries[g].name; g++) { 126719ea8026Sopenharmony_ci bench_define_geometry(&builtin_geometries[g]); 126819ea8026Sopenharmony_ci bench_define_flush(); 126919ea8026Sopenharmony_ci printf("%-*s %7ju %7ju %7ju %7ju %11ju\n", 127019ea8026Sopenharmony_ci name_width, 127119ea8026Sopenharmony_ci builtin_geometries[g].name, 127219ea8026Sopenharmony_ci READ_SIZE, 127319ea8026Sopenharmony_ci PROG_SIZE, 127419ea8026Sopenharmony_ci ERASE_SIZE, 127519ea8026Sopenharmony_ci ERASE_COUNT, 127619ea8026Sopenharmony_ci ERASE_SIZE*ERASE_COUNT); 127719ea8026Sopenharmony_ci } 127819ea8026Sopenharmony_ci} 127919ea8026Sopenharmony_ci 128019ea8026Sopenharmony_ci 128119ea8026Sopenharmony_ci 128219ea8026Sopenharmony_ci// global bench step count 128319ea8026Sopenharmony_cisize_t bench_step = 0; 128419ea8026Sopenharmony_ci 128519ea8026Sopenharmony_civoid perm_run( 128619ea8026Sopenharmony_ci void *data, 128719ea8026Sopenharmony_ci const struct bench_suite *suite, 128819ea8026Sopenharmony_ci const struct bench_case *case_) { 128919ea8026Sopenharmony_ci (void)data; 129019ea8026Sopenharmony_ci 129119ea8026Sopenharmony_ci // skip this step? 129219ea8026Sopenharmony_ci if (!(bench_step >= bench_step_start 129319ea8026Sopenharmony_ci && bench_step < bench_step_stop 129419ea8026Sopenharmony_ci && (bench_step-bench_step_start) % bench_step_step == 0)) { 129519ea8026Sopenharmony_ci bench_step += 1; 129619ea8026Sopenharmony_ci return; 129719ea8026Sopenharmony_ci } 129819ea8026Sopenharmony_ci bench_step += 1; 129919ea8026Sopenharmony_ci 130019ea8026Sopenharmony_ci // filter? 130119ea8026Sopenharmony_ci if (case_->filter && !case_->filter()) { 130219ea8026Sopenharmony_ci printf("skipped "); 130319ea8026Sopenharmony_ci perm_printid(suite, case_); 130419ea8026Sopenharmony_ci printf("\n"); 130519ea8026Sopenharmony_ci return; 130619ea8026Sopenharmony_ci } 130719ea8026Sopenharmony_ci 130819ea8026Sopenharmony_ci // create block device and configuration 130919ea8026Sopenharmony_ci lfs_emubd_t bd; 131019ea8026Sopenharmony_ci 131119ea8026Sopenharmony_ci struct lfs_config cfg = { 131219ea8026Sopenharmony_ci .context = &bd, 131319ea8026Sopenharmony_ci .read = lfs_emubd_read, 131419ea8026Sopenharmony_ci .prog = lfs_emubd_prog, 131519ea8026Sopenharmony_ci .erase = lfs_emubd_erase, 131619ea8026Sopenharmony_ci .sync = lfs_emubd_sync, 131719ea8026Sopenharmony_ci .read_size = READ_SIZE, 131819ea8026Sopenharmony_ci .prog_size = PROG_SIZE, 131919ea8026Sopenharmony_ci .block_size = BLOCK_SIZE, 132019ea8026Sopenharmony_ci .block_count = BLOCK_COUNT, 132119ea8026Sopenharmony_ci .block_cycles = BLOCK_CYCLES, 132219ea8026Sopenharmony_ci .cache_size = CACHE_SIZE, 132319ea8026Sopenharmony_ci .lookahead_size = LOOKAHEAD_SIZE, 132419ea8026Sopenharmony_ci }; 132519ea8026Sopenharmony_ci 132619ea8026Sopenharmony_ci struct lfs_emubd_config bdcfg = { 132719ea8026Sopenharmony_ci .read_size = READ_SIZE, 132819ea8026Sopenharmony_ci .prog_size = PROG_SIZE, 132919ea8026Sopenharmony_ci .erase_size = ERASE_SIZE, 133019ea8026Sopenharmony_ci .erase_count = ERASE_COUNT, 133119ea8026Sopenharmony_ci .erase_value = ERASE_VALUE, 133219ea8026Sopenharmony_ci .erase_cycles = ERASE_CYCLES, 133319ea8026Sopenharmony_ci .badblock_behavior = BADBLOCK_BEHAVIOR, 133419ea8026Sopenharmony_ci .disk_path = bench_disk_path, 133519ea8026Sopenharmony_ci .read_sleep = bench_read_sleep, 133619ea8026Sopenharmony_ci .prog_sleep = bench_prog_sleep, 133719ea8026Sopenharmony_ci .erase_sleep = bench_erase_sleep, 133819ea8026Sopenharmony_ci }; 133919ea8026Sopenharmony_ci 134019ea8026Sopenharmony_ci int err = lfs_emubd_create(&cfg, &bdcfg); 134119ea8026Sopenharmony_ci if (err) { 134219ea8026Sopenharmony_ci fprintf(stderr, "error: could not create block device: %d\n", err); 134319ea8026Sopenharmony_ci exit(-1); 134419ea8026Sopenharmony_ci } 134519ea8026Sopenharmony_ci 134619ea8026Sopenharmony_ci // run the bench 134719ea8026Sopenharmony_ci bench_cfg = &cfg; 134819ea8026Sopenharmony_ci bench_reset(); 134919ea8026Sopenharmony_ci printf("running "); 135019ea8026Sopenharmony_ci perm_printid(suite, case_); 135119ea8026Sopenharmony_ci printf("\n"); 135219ea8026Sopenharmony_ci 135319ea8026Sopenharmony_ci case_->run(&cfg); 135419ea8026Sopenharmony_ci 135519ea8026Sopenharmony_ci printf("finished "); 135619ea8026Sopenharmony_ci perm_printid(suite, case_); 135719ea8026Sopenharmony_ci printf(" %"PRIu64" %"PRIu64" %"PRIu64, 135819ea8026Sopenharmony_ci bench_readed, 135919ea8026Sopenharmony_ci bench_proged, 136019ea8026Sopenharmony_ci bench_erased); 136119ea8026Sopenharmony_ci printf("\n"); 136219ea8026Sopenharmony_ci 136319ea8026Sopenharmony_ci // cleanup 136419ea8026Sopenharmony_ci err = lfs_emubd_destroy(&cfg); 136519ea8026Sopenharmony_ci if (err) { 136619ea8026Sopenharmony_ci fprintf(stderr, "error: could not destroy block device: %d\n", err); 136719ea8026Sopenharmony_ci exit(-1); 136819ea8026Sopenharmony_ci } 136919ea8026Sopenharmony_ci} 137019ea8026Sopenharmony_ci 137119ea8026Sopenharmony_cistatic void run(void) { 137219ea8026Sopenharmony_ci // ignore disconnected pipes 137319ea8026Sopenharmony_ci signal(SIGPIPE, SIG_IGN); 137419ea8026Sopenharmony_ci 137519ea8026Sopenharmony_ci for (size_t t = 0; t < bench_id_count; t++) { 137619ea8026Sopenharmony_ci for (size_t i = 0; i < BENCH_SUITE_COUNT; i++) { 137719ea8026Sopenharmony_ci bench_define_suite(&bench_suites[i]); 137819ea8026Sopenharmony_ci 137919ea8026Sopenharmony_ci for (size_t j = 0; j < bench_suites[i].case_count; j++) { 138019ea8026Sopenharmony_ci // does neither suite nor case name match? 138119ea8026Sopenharmony_ci if (bench_ids[t].name && !( 138219ea8026Sopenharmony_ci strcmp(bench_ids[t].name, 138319ea8026Sopenharmony_ci bench_suites[i].name) == 0 138419ea8026Sopenharmony_ci || strcmp(bench_ids[t].name, 138519ea8026Sopenharmony_ci bench_suites[i].cases[j].name) == 0)) { 138619ea8026Sopenharmony_ci continue; 138719ea8026Sopenharmony_ci } 138819ea8026Sopenharmony_ci 138919ea8026Sopenharmony_ci case_forperm( 139019ea8026Sopenharmony_ci &bench_suites[i], 139119ea8026Sopenharmony_ci &bench_suites[i].cases[j], 139219ea8026Sopenharmony_ci bench_ids[t].defines, 139319ea8026Sopenharmony_ci bench_ids[t].define_count, 139419ea8026Sopenharmony_ci perm_run, 139519ea8026Sopenharmony_ci NULL); 139619ea8026Sopenharmony_ci } 139719ea8026Sopenharmony_ci } 139819ea8026Sopenharmony_ci } 139919ea8026Sopenharmony_ci} 140019ea8026Sopenharmony_ci 140119ea8026Sopenharmony_ci 140219ea8026Sopenharmony_ci 140319ea8026Sopenharmony_ci// option handling 140419ea8026Sopenharmony_cienum opt_flags { 140519ea8026Sopenharmony_ci OPT_HELP = 'h', 140619ea8026Sopenharmony_ci OPT_SUMMARY = 'Y', 140719ea8026Sopenharmony_ci OPT_LIST_SUITES = 'l', 140819ea8026Sopenharmony_ci OPT_LIST_CASES = 'L', 140919ea8026Sopenharmony_ci OPT_LIST_SUITE_PATHS = 1, 141019ea8026Sopenharmony_ci OPT_LIST_CASE_PATHS = 2, 141119ea8026Sopenharmony_ci OPT_LIST_DEFINES = 3, 141219ea8026Sopenharmony_ci OPT_LIST_PERMUTATION_DEFINES = 4, 141319ea8026Sopenharmony_ci OPT_LIST_IMPLICIT_DEFINES = 5, 141419ea8026Sopenharmony_ci OPT_LIST_GEOMETRIES = 6, 141519ea8026Sopenharmony_ci OPT_DEFINE = 'D', 141619ea8026Sopenharmony_ci OPT_GEOMETRY = 'G', 141719ea8026Sopenharmony_ci OPT_STEP = 's', 141819ea8026Sopenharmony_ci OPT_DISK = 'd', 141919ea8026Sopenharmony_ci OPT_TRACE = 't', 142019ea8026Sopenharmony_ci OPT_TRACE_BACKTRACE = 7, 142119ea8026Sopenharmony_ci OPT_TRACE_PERIOD = 8, 142219ea8026Sopenharmony_ci OPT_TRACE_FREQ = 9, 142319ea8026Sopenharmony_ci OPT_READ_SLEEP = 10, 142419ea8026Sopenharmony_ci OPT_PROG_SLEEP = 11, 142519ea8026Sopenharmony_ci OPT_ERASE_SLEEP = 12, 142619ea8026Sopenharmony_ci}; 142719ea8026Sopenharmony_ci 142819ea8026Sopenharmony_ciconst char *short_opts = "hYlLD:G:s:d:t:"; 142919ea8026Sopenharmony_ci 143019ea8026Sopenharmony_ciconst struct option long_opts[] = { 143119ea8026Sopenharmony_ci {"help", no_argument, NULL, OPT_HELP}, 143219ea8026Sopenharmony_ci {"summary", no_argument, NULL, OPT_SUMMARY}, 143319ea8026Sopenharmony_ci {"list-suites", no_argument, NULL, OPT_LIST_SUITES}, 143419ea8026Sopenharmony_ci {"list-cases", no_argument, NULL, OPT_LIST_CASES}, 143519ea8026Sopenharmony_ci {"list-suite-paths", no_argument, NULL, OPT_LIST_SUITE_PATHS}, 143619ea8026Sopenharmony_ci {"list-case-paths", no_argument, NULL, OPT_LIST_CASE_PATHS}, 143719ea8026Sopenharmony_ci {"list-defines", no_argument, NULL, OPT_LIST_DEFINES}, 143819ea8026Sopenharmony_ci {"list-permutation-defines", 143919ea8026Sopenharmony_ci no_argument, NULL, OPT_LIST_PERMUTATION_DEFINES}, 144019ea8026Sopenharmony_ci {"list-implicit-defines", 144119ea8026Sopenharmony_ci no_argument, NULL, OPT_LIST_IMPLICIT_DEFINES}, 144219ea8026Sopenharmony_ci {"list-geometries", no_argument, NULL, OPT_LIST_GEOMETRIES}, 144319ea8026Sopenharmony_ci {"define", required_argument, NULL, OPT_DEFINE}, 144419ea8026Sopenharmony_ci {"geometry", required_argument, NULL, OPT_GEOMETRY}, 144519ea8026Sopenharmony_ci {"step", required_argument, NULL, OPT_STEP}, 144619ea8026Sopenharmony_ci {"disk", required_argument, NULL, OPT_DISK}, 144719ea8026Sopenharmony_ci {"trace", required_argument, NULL, OPT_TRACE}, 144819ea8026Sopenharmony_ci {"trace-backtrace", no_argument, NULL, OPT_TRACE_BACKTRACE}, 144919ea8026Sopenharmony_ci {"trace-period", required_argument, NULL, OPT_TRACE_PERIOD}, 145019ea8026Sopenharmony_ci {"trace-freq", required_argument, NULL, OPT_TRACE_FREQ}, 145119ea8026Sopenharmony_ci {"read-sleep", required_argument, NULL, OPT_READ_SLEEP}, 145219ea8026Sopenharmony_ci {"prog-sleep", required_argument, NULL, OPT_PROG_SLEEP}, 145319ea8026Sopenharmony_ci {"erase-sleep", required_argument, NULL, OPT_ERASE_SLEEP}, 145419ea8026Sopenharmony_ci {NULL, 0, NULL, 0}, 145519ea8026Sopenharmony_ci}; 145619ea8026Sopenharmony_ci 145719ea8026Sopenharmony_ciconst char *const help_text[] = { 145819ea8026Sopenharmony_ci "Show this help message.", 145919ea8026Sopenharmony_ci "Show quick summary.", 146019ea8026Sopenharmony_ci "List bench suites.", 146119ea8026Sopenharmony_ci "List bench cases.", 146219ea8026Sopenharmony_ci "List the path for each bench suite.", 146319ea8026Sopenharmony_ci "List the path and line number for each bench case.", 146419ea8026Sopenharmony_ci "List all defines in this bench-runner.", 146519ea8026Sopenharmony_ci "List explicit defines in this bench-runner.", 146619ea8026Sopenharmony_ci "List implicit defines in this bench-runner.", 146719ea8026Sopenharmony_ci "List the available disk geometries.", 146819ea8026Sopenharmony_ci "Override a bench define.", 146919ea8026Sopenharmony_ci "Comma-separated list of disk geometries to bench.", 147019ea8026Sopenharmony_ci "Comma-separated range of bench permutations to run (start,stop,step).", 147119ea8026Sopenharmony_ci "Direct block device operations to this file.", 147219ea8026Sopenharmony_ci "Direct trace output to this file.", 147319ea8026Sopenharmony_ci "Include a backtrace with every trace statement.", 147419ea8026Sopenharmony_ci "Sample trace output at this period in cycles.", 147519ea8026Sopenharmony_ci "Sample trace output at this frequency in hz.", 147619ea8026Sopenharmony_ci "Artificial read delay in seconds.", 147719ea8026Sopenharmony_ci "Artificial prog delay in seconds.", 147819ea8026Sopenharmony_ci "Artificial erase delay in seconds.", 147919ea8026Sopenharmony_ci}; 148019ea8026Sopenharmony_ci 148119ea8026Sopenharmony_ciint main(int argc, char **argv) { 148219ea8026Sopenharmony_ci void (*op)(void) = run; 148319ea8026Sopenharmony_ci 148419ea8026Sopenharmony_ci size_t bench_override_capacity = 0; 148519ea8026Sopenharmony_ci size_t bench_geometry_capacity = 0; 148619ea8026Sopenharmony_ci size_t bench_id_capacity = 0; 148719ea8026Sopenharmony_ci 148819ea8026Sopenharmony_ci // parse options 148919ea8026Sopenharmony_ci while (true) { 149019ea8026Sopenharmony_ci int c = getopt_long(argc, argv, short_opts, long_opts, NULL); 149119ea8026Sopenharmony_ci switch (c) { 149219ea8026Sopenharmony_ci // generate help message 149319ea8026Sopenharmony_ci case OPT_HELP: { 149419ea8026Sopenharmony_ci printf("usage: %s [options] [bench_id]\n", argv[0]); 149519ea8026Sopenharmony_ci printf("\n"); 149619ea8026Sopenharmony_ci 149719ea8026Sopenharmony_ci printf("options:\n"); 149819ea8026Sopenharmony_ci size_t i = 0; 149919ea8026Sopenharmony_ci while (long_opts[i].name) { 150019ea8026Sopenharmony_ci size_t indent; 150119ea8026Sopenharmony_ci if (long_opts[i].has_arg == no_argument) { 150219ea8026Sopenharmony_ci if (long_opts[i].val >= '0' && long_opts[i].val < 'z') { 150319ea8026Sopenharmony_ci indent = printf(" -%c, --%s ", 150419ea8026Sopenharmony_ci long_opts[i].val, 150519ea8026Sopenharmony_ci long_opts[i].name); 150619ea8026Sopenharmony_ci } else { 150719ea8026Sopenharmony_ci indent = printf(" --%s ", 150819ea8026Sopenharmony_ci long_opts[i].name); 150919ea8026Sopenharmony_ci } 151019ea8026Sopenharmony_ci } else { 151119ea8026Sopenharmony_ci if (long_opts[i].val >= '0' && long_opts[i].val < 'z') { 151219ea8026Sopenharmony_ci indent = printf(" -%c %s, --%s %s ", 151319ea8026Sopenharmony_ci long_opts[i].val, 151419ea8026Sopenharmony_ci long_opts[i].name, 151519ea8026Sopenharmony_ci long_opts[i].name, 151619ea8026Sopenharmony_ci long_opts[i].name); 151719ea8026Sopenharmony_ci } else { 151819ea8026Sopenharmony_ci indent = printf(" --%s %s ", 151919ea8026Sopenharmony_ci long_opts[i].name, 152019ea8026Sopenharmony_ci long_opts[i].name); 152119ea8026Sopenharmony_ci } 152219ea8026Sopenharmony_ci } 152319ea8026Sopenharmony_ci 152419ea8026Sopenharmony_ci // a quick, hacky, byte-level method for text wrapping 152519ea8026Sopenharmony_ci size_t len = strlen(help_text[i]); 152619ea8026Sopenharmony_ci size_t j = 0; 152719ea8026Sopenharmony_ci if (indent < 24) { 152819ea8026Sopenharmony_ci printf("%*s %.80s\n", 152919ea8026Sopenharmony_ci (int)(24-1-indent), 153019ea8026Sopenharmony_ci "", 153119ea8026Sopenharmony_ci &help_text[i][j]); 153219ea8026Sopenharmony_ci j += 80; 153319ea8026Sopenharmony_ci } else { 153419ea8026Sopenharmony_ci printf("\n"); 153519ea8026Sopenharmony_ci } 153619ea8026Sopenharmony_ci 153719ea8026Sopenharmony_ci while (j < len) { 153819ea8026Sopenharmony_ci printf("%24s%.80s\n", "", &help_text[i][j]); 153919ea8026Sopenharmony_ci j += 80; 154019ea8026Sopenharmony_ci } 154119ea8026Sopenharmony_ci 154219ea8026Sopenharmony_ci i += 1; 154319ea8026Sopenharmony_ci } 154419ea8026Sopenharmony_ci 154519ea8026Sopenharmony_ci printf("\n"); 154619ea8026Sopenharmony_ci exit(0); 154719ea8026Sopenharmony_ci } 154819ea8026Sopenharmony_ci // summary/list flags 154919ea8026Sopenharmony_ci case OPT_SUMMARY: 155019ea8026Sopenharmony_ci op = summary; 155119ea8026Sopenharmony_ci break; 155219ea8026Sopenharmony_ci case OPT_LIST_SUITES: 155319ea8026Sopenharmony_ci op = list_suites; 155419ea8026Sopenharmony_ci break; 155519ea8026Sopenharmony_ci case OPT_LIST_CASES: 155619ea8026Sopenharmony_ci op = list_cases; 155719ea8026Sopenharmony_ci break; 155819ea8026Sopenharmony_ci case OPT_LIST_SUITE_PATHS: 155919ea8026Sopenharmony_ci op = list_suite_paths; 156019ea8026Sopenharmony_ci break; 156119ea8026Sopenharmony_ci case OPT_LIST_CASE_PATHS: 156219ea8026Sopenharmony_ci op = list_case_paths; 156319ea8026Sopenharmony_ci break; 156419ea8026Sopenharmony_ci case OPT_LIST_DEFINES: 156519ea8026Sopenharmony_ci op = list_defines; 156619ea8026Sopenharmony_ci break; 156719ea8026Sopenharmony_ci case OPT_LIST_PERMUTATION_DEFINES: 156819ea8026Sopenharmony_ci op = list_permutation_defines; 156919ea8026Sopenharmony_ci break; 157019ea8026Sopenharmony_ci case OPT_LIST_IMPLICIT_DEFINES: 157119ea8026Sopenharmony_ci op = list_implicit_defines; 157219ea8026Sopenharmony_ci break; 157319ea8026Sopenharmony_ci case OPT_LIST_GEOMETRIES: 157419ea8026Sopenharmony_ci op = list_geometries; 157519ea8026Sopenharmony_ci break; 157619ea8026Sopenharmony_ci // configuration 157719ea8026Sopenharmony_ci case OPT_DEFINE: { 157819ea8026Sopenharmony_ci // allocate space 157919ea8026Sopenharmony_ci bench_override_t *override = mappend( 158019ea8026Sopenharmony_ci (void**)&bench_overrides, 158119ea8026Sopenharmony_ci sizeof(bench_override_t), 158219ea8026Sopenharmony_ci &bench_override_count, 158319ea8026Sopenharmony_ci &bench_override_capacity); 158419ea8026Sopenharmony_ci 158519ea8026Sopenharmony_ci // parse into string key/intmax_t value, cannibalizing the 158619ea8026Sopenharmony_ci // arg in the process 158719ea8026Sopenharmony_ci char *sep = strchr(optarg, '='); 158819ea8026Sopenharmony_ci char *parsed = NULL; 158919ea8026Sopenharmony_ci if (!sep) { 159019ea8026Sopenharmony_ci goto invalid_define; 159119ea8026Sopenharmony_ci } 159219ea8026Sopenharmony_ci *sep = '\0'; 159319ea8026Sopenharmony_ci override->name = optarg; 159419ea8026Sopenharmony_ci optarg = sep+1; 159519ea8026Sopenharmony_ci 159619ea8026Sopenharmony_ci // parse comma-separated permutations 159719ea8026Sopenharmony_ci { 159819ea8026Sopenharmony_ci override->defines = NULL; 159919ea8026Sopenharmony_ci override->permutations = 0; 160019ea8026Sopenharmony_ci size_t override_capacity = 0; 160119ea8026Sopenharmony_ci while (true) { 160219ea8026Sopenharmony_ci optarg += strspn(optarg, " "); 160319ea8026Sopenharmony_ci 160419ea8026Sopenharmony_ci if (strncmp(optarg, "range", strlen("range")) == 0) { 160519ea8026Sopenharmony_ci // range of values 160619ea8026Sopenharmony_ci optarg += strlen("range"); 160719ea8026Sopenharmony_ci optarg += strspn(optarg, " "); 160819ea8026Sopenharmony_ci if (*optarg != '(') { 160919ea8026Sopenharmony_ci goto invalid_define; 161019ea8026Sopenharmony_ci } 161119ea8026Sopenharmony_ci optarg += 1; 161219ea8026Sopenharmony_ci 161319ea8026Sopenharmony_ci intmax_t start = strtoumax(optarg, &parsed, 0); 161419ea8026Sopenharmony_ci intmax_t stop = -1; 161519ea8026Sopenharmony_ci intmax_t step = 1; 161619ea8026Sopenharmony_ci // allow empty string for start=0 161719ea8026Sopenharmony_ci if (parsed == optarg) { 161819ea8026Sopenharmony_ci start = 0; 161919ea8026Sopenharmony_ci } 162019ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 162119ea8026Sopenharmony_ci 162219ea8026Sopenharmony_ci if (*optarg != ',' && *optarg != ')') { 162319ea8026Sopenharmony_ci goto invalid_define; 162419ea8026Sopenharmony_ci } 162519ea8026Sopenharmony_ci 162619ea8026Sopenharmony_ci if (*optarg == ',') { 162719ea8026Sopenharmony_ci optarg += 1; 162819ea8026Sopenharmony_ci stop = strtoumax(optarg, &parsed, 0); 162919ea8026Sopenharmony_ci // allow empty string for stop=end 163019ea8026Sopenharmony_ci if (parsed == optarg) { 163119ea8026Sopenharmony_ci stop = -1; 163219ea8026Sopenharmony_ci } 163319ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 163419ea8026Sopenharmony_ci 163519ea8026Sopenharmony_ci if (*optarg != ',' && *optarg != ')') { 163619ea8026Sopenharmony_ci goto invalid_define; 163719ea8026Sopenharmony_ci } 163819ea8026Sopenharmony_ci 163919ea8026Sopenharmony_ci if (*optarg == ',') { 164019ea8026Sopenharmony_ci optarg += 1; 164119ea8026Sopenharmony_ci step = strtoumax(optarg, &parsed, 0); 164219ea8026Sopenharmony_ci // allow empty string for stop=1 164319ea8026Sopenharmony_ci if (parsed == optarg) { 164419ea8026Sopenharmony_ci step = 1; 164519ea8026Sopenharmony_ci } 164619ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 164719ea8026Sopenharmony_ci 164819ea8026Sopenharmony_ci if (*optarg != ')') { 164919ea8026Sopenharmony_ci goto invalid_define; 165019ea8026Sopenharmony_ci } 165119ea8026Sopenharmony_ci } 165219ea8026Sopenharmony_ci } else { 165319ea8026Sopenharmony_ci // single value = stop only 165419ea8026Sopenharmony_ci stop = start; 165519ea8026Sopenharmony_ci start = 0; 165619ea8026Sopenharmony_ci } 165719ea8026Sopenharmony_ci 165819ea8026Sopenharmony_ci if (*optarg != ')') { 165919ea8026Sopenharmony_ci goto invalid_define; 166019ea8026Sopenharmony_ci } 166119ea8026Sopenharmony_ci optarg += 1; 166219ea8026Sopenharmony_ci 166319ea8026Sopenharmony_ci // calculate the range of values 166419ea8026Sopenharmony_ci assert(step != 0); 166519ea8026Sopenharmony_ci for (intmax_t i = start; 166619ea8026Sopenharmony_ci (step < 0) 166719ea8026Sopenharmony_ci ? i > stop 166819ea8026Sopenharmony_ci : (uintmax_t)i < (uintmax_t)stop; 166919ea8026Sopenharmony_ci i += step) { 167019ea8026Sopenharmony_ci *(intmax_t*)mappend( 167119ea8026Sopenharmony_ci (void**)&override->defines, 167219ea8026Sopenharmony_ci sizeof(intmax_t), 167319ea8026Sopenharmony_ci &override->permutations, 167419ea8026Sopenharmony_ci &override_capacity) = i; 167519ea8026Sopenharmony_ci } 167619ea8026Sopenharmony_ci } else if (*optarg != '\0') { 167719ea8026Sopenharmony_ci // single value 167819ea8026Sopenharmony_ci intmax_t define = strtoimax(optarg, &parsed, 0); 167919ea8026Sopenharmony_ci if (parsed == optarg) { 168019ea8026Sopenharmony_ci goto invalid_define; 168119ea8026Sopenharmony_ci } 168219ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 168319ea8026Sopenharmony_ci *(intmax_t*)mappend( 168419ea8026Sopenharmony_ci (void**)&override->defines, 168519ea8026Sopenharmony_ci sizeof(intmax_t), 168619ea8026Sopenharmony_ci &override->permutations, 168719ea8026Sopenharmony_ci &override_capacity) = define; 168819ea8026Sopenharmony_ci } else { 168919ea8026Sopenharmony_ci break; 169019ea8026Sopenharmony_ci } 169119ea8026Sopenharmony_ci 169219ea8026Sopenharmony_ci if (*optarg == ',') { 169319ea8026Sopenharmony_ci optarg += 1; 169419ea8026Sopenharmony_ci } 169519ea8026Sopenharmony_ci } 169619ea8026Sopenharmony_ci } 169719ea8026Sopenharmony_ci assert(override->permutations > 0); 169819ea8026Sopenharmony_ci break; 169919ea8026Sopenharmony_ci 170019ea8026Sopenharmony_ciinvalid_define: 170119ea8026Sopenharmony_ci fprintf(stderr, "error: invalid define: %s\n", optarg); 170219ea8026Sopenharmony_ci exit(-1); 170319ea8026Sopenharmony_ci } 170419ea8026Sopenharmony_ci case OPT_GEOMETRY: { 170519ea8026Sopenharmony_ci // reset our geometry scenarios 170619ea8026Sopenharmony_ci if (bench_geometry_capacity > 0) { 170719ea8026Sopenharmony_ci free((bench_geometry_t*)bench_geometries); 170819ea8026Sopenharmony_ci } 170919ea8026Sopenharmony_ci bench_geometries = NULL; 171019ea8026Sopenharmony_ci bench_geometry_count = 0; 171119ea8026Sopenharmony_ci bench_geometry_capacity = 0; 171219ea8026Sopenharmony_ci 171319ea8026Sopenharmony_ci // parse the comma separated list of disk geometries 171419ea8026Sopenharmony_ci while (*optarg) { 171519ea8026Sopenharmony_ci // allocate space 171619ea8026Sopenharmony_ci bench_geometry_t *geometry = mappend( 171719ea8026Sopenharmony_ci (void**)&bench_geometries, 171819ea8026Sopenharmony_ci sizeof(bench_geometry_t), 171919ea8026Sopenharmony_ci &bench_geometry_count, 172019ea8026Sopenharmony_ci &bench_geometry_capacity); 172119ea8026Sopenharmony_ci 172219ea8026Sopenharmony_ci // parse the disk geometry 172319ea8026Sopenharmony_ci optarg += strspn(optarg, " "); 172419ea8026Sopenharmony_ci 172519ea8026Sopenharmony_ci // named disk geometry 172619ea8026Sopenharmony_ci size_t len = strcspn(optarg, " ,"); 172719ea8026Sopenharmony_ci for (size_t i = 0; builtin_geometries[i].name; i++) { 172819ea8026Sopenharmony_ci if (len == strlen(builtin_geometries[i].name) 172919ea8026Sopenharmony_ci && memcmp(optarg, 173019ea8026Sopenharmony_ci builtin_geometries[i].name, 173119ea8026Sopenharmony_ci len) == 0) { 173219ea8026Sopenharmony_ci *geometry = builtin_geometries[i]; 173319ea8026Sopenharmony_ci optarg += len; 173419ea8026Sopenharmony_ci goto geometry_next; 173519ea8026Sopenharmony_ci } 173619ea8026Sopenharmony_ci } 173719ea8026Sopenharmony_ci 173819ea8026Sopenharmony_ci // comma-separated read/prog/erase/count 173919ea8026Sopenharmony_ci if (*optarg == '{') { 174019ea8026Sopenharmony_ci lfs_size_t sizes[4]; 174119ea8026Sopenharmony_ci size_t count = 0; 174219ea8026Sopenharmony_ci 174319ea8026Sopenharmony_ci char *s = optarg + 1; 174419ea8026Sopenharmony_ci while (count < 4) { 174519ea8026Sopenharmony_ci char *parsed = NULL; 174619ea8026Sopenharmony_ci sizes[count] = strtoumax(s, &parsed, 0); 174719ea8026Sopenharmony_ci count += 1; 174819ea8026Sopenharmony_ci 174919ea8026Sopenharmony_ci s = parsed + strspn(parsed, " "); 175019ea8026Sopenharmony_ci if (*s == ',') { 175119ea8026Sopenharmony_ci s += 1; 175219ea8026Sopenharmony_ci continue; 175319ea8026Sopenharmony_ci } else if (*s == '}') { 175419ea8026Sopenharmony_ci s += 1; 175519ea8026Sopenharmony_ci break; 175619ea8026Sopenharmony_ci } else { 175719ea8026Sopenharmony_ci goto geometry_unknown; 175819ea8026Sopenharmony_ci } 175919ea8026Sopenharmony_ci } 176019ea8026Sopenharmony_ci 176119ea8026Sopenharmony_ci // allow implicit r=p and p=e for common geometries 176219ea8026Sopenharmony_ci memset(geometry, 0, sizeof(bench_geometry_t)); 176319ea8026Sopenharmony_ci if (count >= 3) { 176419ea8026Sopenharmony_ci geometry->defines[READ_SIZE_i] 176519ea8026Sopenharmony_ci = BENCH_LIT(sizes[0]); 176619ea8026Sopenharmony_ci geometry->defines[PROG_SIZE_i] 176719ea8026Sopenharmony_ci = BENCH_LIT(sizes[1]); 176819ea8026Sopenharmony_ci geometry->defines[ERASE_SIZE_i] 176919ea8026Sopenharmony_ci = BENCH_LIT(sizes[2]); 177019ea8026Sopenharmony_ci } else if (count >= 2) { 177119ea8026Sopenharmony_ci geometry->defines[PROG_SIZE_i] 177219ea8026Sopenharmony_ci = BENCH_LIT(sizes[0]); 177319ea8026Sopenharmony_ci geometry->defines[ERASE_SIZE_i] 177419ea8026Sopenharmony_ci = BENCH_LIT(sizes[1]); 177519ea8026Sopenharmony_ci } else { 177619ea8026Sopenharmony_ci geometry->defines[ERASE_SIZE_i] 177719ea8026Sopenharmony_ci = BENCH_LIT(sizes[0]); 177819ea8026Sopenharmony_ci } 177919ea8026Sopenharmony_ci if (count >= 4) { 178019ea8026Sopenharmony_ci geometry->defines[ERASE_COUNT_i] 178119ea8026Sopenharmony_ci = BENCH_LIT(sizes[3]); 178219ea8026Sopenharmony_ci } 178319ea8026Sopenharmony_ci optarg = s; 178419ea8026Sopenharmony_ci goto geometry_next; 178519ea8026Sopenharmony_ci } 178619ea8026Sopenharmony_ci 178719ea8026Sopenharmony_ci // leb16-encoded read/prog/erase/count 178819ea8026Sopenharmony_ci if (*optarg == ':') { 178919ea8026Sopenharmony_ci lfs_size_t sizes[4]; 179019ea8026Sopenharmony_ci size_t count = 0; 179119ea8026Sopenharmony_ci 179219ea8026Sopenharmony_ci char *s = optarg + 1; 179319ea8026Sopenharmony_ci while (true) { 179419ea8026Sopenharmony_ci char *parsed = NULL; 179519ea8026Sopenharmony_ci uintmax_t x = leb16_parse(s, &parsed); 179619ea8026Sopenharmony_ci if (parsed == s || count >= 4) { 179719ea8026Sopenharmony_ci break; 179819ea8026Sopenharmony_ci } 179919ea8026Sopenharmony_ci 180019ea8026Sopenharmony_ci sizes[count] = x; 180119ea8026Sopenharmony_ci count += 1; 180219ea8026Sopenharmony_ci s = parsed; 180319ea8026Sopenharmony_ci } 180419ea8026Sopenharmony_ci 180519ea8026Sopenharmony_ci // allow implicit r=p and p=e for common geometries 180619ea8026Sopenharmony_ci memset(geometry, 0, sizeof(bench_geometry_t)); 180719ea8026Sopenharmony_ci if (count >= 3) { 180819ea8026Sopenharmony_ci geometry->defines[READ_SIZE_i] 180919ea8026Sopenharmony_ci = BENCH_LIT(sizes[0]); 181019ea8026Sopenharmony_ci geometry->defines[PROG_SIZE_i] 181119ea8026Sopenharmony_ci = BENCH_LIT(sizes[1]); 181219ea8026Sopenharmony_ci geometry->defines[ERASE_SIZE_i] 181319ea8026Sopenharmony_ci = BENCH_LIT(sizes[2]); 181419ea8026Sopenharmony_ci } else if (count >= 2) { 181519ea8026Sopenharmony_ci geometry->defines[PROG_SIZE_i] 181619ea8026Sopenharmony_ci = BENCH_LIT(sizes[0]); 181719ea8026Sopenharmony_ci geometry->defines[ERASE_SIZE_i] 181819ea8026Sopenharmony_ci = BENCH_LIT(sizes[1]); 181919ea8026Sopenharmony_ci } else { 182019ea8026Sopenharmony_ci geometry->defines[ERASE_SIZE_i] 182119ea8026Sopenharmony_ci = BENCH_LIT(sizes[0]); 182219ea8026Sopenharmony_ci } 182319ea8026Sopenharmony_ci if (count >= 4) { 182419ea8026Sopenharmony_ci geometry->defines[ERASE_COUNT_i] 182519ea8026Sopenharmony_ci = BENCH_LIT(sizes[3]); 182619ea8026Sopenharmony_ci } 182719ea8026Sopenharmony_ci optarg = s; 182819ea8026Sopenharmony_ci goto geometry_next; 182919ea8026Sopenharmony_ci } 183019ea8026Sopenharmony_ci 183119ea8026Sopenharmony_cigeometry_unknown: 183219ea8026Sopenharmony_ci // unknown scenario? 183319ea8026Sopenharmony_ci fprintf(stderr, "error: unknown disk geometry: %s\n", 183419ea8026Sopenharmony_ci optarg); 183519ea8026Sopenharmony_ci exit(-1); 183619ea8026Sopenharmony_ci 183719ea8026Sopenharmony_cigeometry_next: 183819ea8026Sopenharmony_ci optarg += strspn(optarg, " "); 183919ea8026Sopenharmony_ci if (*optarg == ',') { 184019ea8026Sopenharmony_ci optarg += 1; 184119ea8026Sopenharmony_ci } else if (*optarg == '\0') { 184219ea8026Sopenharmony_ci break; 184319ea8026Sopenharmony_ci } else { 184419ea8026Sopenharmony_ci goto geometry_unknown; 184519ea8026Sopenharmony_ci } 184619ea8026Sopenharmony_ci } 184719ea8026Sopenharmony_ci break; 184819ea8026Sopenharmony_ci } 184919ea8026Sopenharmony_ci case OPT_STEP: { 185019ea8026Sopenharmony_ci char *parsed = NULL; 185119ea8026Sopenharmony_ci bench_step_start = strtoumax(optarg, &parsed, 0); 185219ea8026Sopenharmony_ci bench_step_stop = -1; 185319ea8026Sopenharmony_ci bench_step_step = 1; 185419ea8026Sopenharmony_ci // allow empty string for start=0 185519ea8026Sopenharmony_ci if (parsed == optarg) { 185619ea8026Sopenharmony_ci bench_step_start = 0; 185719ea8026Sopenharmony_ci } 185819ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 185919ea8026Sopenharmony_ci 186019ea8026Sopenharmony_ci if (*optarg != ',' && *optarg != '\0') { 186119ea8026Sopenharmony_ci goto step_unknown; 186219ea8026Sopenharmony_ci } 186319ea8026Sopenharmony_ci 186419ea8026Sopenharmony_ci if (*optarg == ',') { 186519ea8026Sopenharmony_ci optarg += 1; 186619ea8026Sopenharmony_ci bench_step_stop = strtoumax(optarg, &parsed, 0); 186719ea8026Sopenharmony_ci // allow empty string for stop=end 186819ea8026Sopenharmony_ci if (parsed == optarg) { 186919ea8026Sopenharmony_ci bench_step_stop = -1; 187019ea8026Sopenharmony_ci } 187119ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 187219ea8026Sopenharmony_ci 187319ea8026Sopenharmony_ci if (*optarg != ',' && *optarg != '\0') { 187419ea8026Sopenharmony_ci goto step_unknown; 187519ea8026Sopenharmony_ci } 187619ea8026Sopenharmony_ci 187719ea8026Sopenharmony_ci if (*optarg == ',') { 187819ea8026Sopenharmony_ci optarg += 1; 187919ea8026Sopenharmony_ci bench_step_step = strtoumax(optarg, &parsed, 0); 188019ea8026Sopenharmony_ci // allow empty string for stop=1 188119ea8026Sopenharmony_ci if (parsed == optarg) { 188219ea8026Sopenharmony_ci bench_step_step = 1; 188319ea8026Sopenharmony_ci } 188419ea8026Sopenharmony_ci optarg = parsed + strspn(parsed, " "); 188519ea8026Sopenharmony_ci 188619ea8026Sopenharmony_ci if (*optarg != '\0') { 188719ea8026Sopenharmony_ci goto step_unknown; 188819ea8026Sopenharmony_ci } 188919ea8026Sopenharmony_ci } 189019ea8026Sopenharmony_ci } else { 189119ea8026Sopenharmony_ci // single value = stop only 189219ea8026Sopenharmony_ci bench_step_stop = bench_step_start; 189319ea8026Sopenharmony_ci bench_step_start = 0; 189419ea8026Sopenharmony_ci } 189519ea8026Sopenharmony_ci 189619ea8026Sopenharmony_ci break; 189719ea8026Sopenharmony_cistep_unknown: 189819ea8026Sopenharmony_ci fprintf(stderr, "error: invalid step: %s\n", optarg); 189919ea8026Sopenharmony_ci exit(-1); 190019ea8026Sopenharmony_ci } 190119ea8026Sopenharmony_ci case OPT_DISK: 190219ea8026Sopenharmony_ci bench_disk_path = optarg; 190319ea8026Sopenharmony_ci break; 190419ea8026Sopenharmony_ci case OPT_TRACE: 190519ea8026Sopenharmony_ci bench_trace_path = optarg; 190619ea8026Sopenharmony_ci break; 190719ea8026Sopenharmony_ci case OPT_TRACE_BACKTRACE: 190819ea8026Sopenharmony_ci bench_trace_backtrace = true; 190919ea8026Sopenharmony_ci break; 191019ea8026Sopenharmony_ci case OPT_TRACE_PERIOD: { 191119ea8026Sopenharmony_ci char *parsed = NULL; 191219ea8026Sopenharmony_ci bench_trace_period = strtoumax(optarg, &parsed, 0); 191319ea8026Sopenharmony_ci if (parsed == optarg) { 191419ea8026Sopenharmony_ci fprintf(stderr, "error: invalid trace-period: %s\n", optarg); 191519ea8026Sopenharmony_ci exit(-1); 191619ea8026Sopenharmony_ci } 191719ea8026Sopenharmony_ci break; 191819ea8026Sopenharmony_ci } 191919ea8026Sopenharmony_ci case OPT_TRACE_FREQ: { 192019ea8026Sopenharmony_ci char *parsed = NULL; 192119ea8026Sopenharmony_ci bench_trace_freq = strtoumax(optarg, &parsed, 0); 192219ea8026Sopenharmony_ci if (parsed == optarg) { 192319ea8026Sopenharmony_ci fprintf(stderr, "error: invalid trace-freq: %s\n", optarg); 192419ea8026Sopenharmony_ci exit(-1); 192519ea8026Sopenharmony_ci } 192619ea8026Sopenharmony_ci break; 192719ea8026Sopenharmony_ci } 192819ea8026Sopenharmony_ci case OPT_READ_SLEEP: { 192919ea8026Sopenharmony_ci char *parsed = NULL; 193019ea8026Sopenharmony_ci double read_sleep = strtod(optarg, &parsed); 193119ea8026Sopenharmony_ci if (parsed == optarg) { 193219ea8026Sopenharmony_ci fprintf(stderr, "error: invalid read-sleep: %s\n", optarg); 193319ea8026Sopenharmony_ci exit(-1); 193419ea8026Sopenharmony_ci } 193519ea8026Sopenharmony_ci bench_read_sleep = read_sleep*1.0e9; 193619ea8026Sopenharmony_ci break; 193719ea8026Sopenharmony_ci } 193819ea8026Sopenharmony_ci case OPT_PROG_SLEEP: { 193919ea8026Sopenharmony_ci char *parsed = NULL; 194019ea8026Sopenharmony_ci double prog_sleep = strtod(optarg, &parsed); 194119ea8026Sopenharmony_ci if (parsed == optarg) { 194219ea8026Sopenharmony_ci fprintf(stderr, "error: invalid prog-sleep: %s\n", optarg); 194319ea8026Sopenharmony_ci exit(-1); 194419ea8026Sopenharmony_ci } 194519ea8026Sopenharmony_ci bench_prog_sleep = prog_sleep*1.0e9; 194619ea8026Sopenharmony_ci break; 194719ea8026Sopenharmony_ci } 194819ea8026Sopenharmony_ci case OPT_ERASE_SLEEP: { 194919ea8026Sopenharmony_ci char *parsed = NULL; 195019ea8026Sopenharmony_ci double erase_sleep = strtod(optarg, &parsed); 195119ea8026Sopenharmony_ci if (parsed == optarg) { 195219ea8026Sopenharmony_ci fprintf(stderr, "error: invalid erase-sleep: %s\n", optarg); 195319ea8026Sopenharmony_ci exit(-1); 195419ea8026Sopenharmony_ci } 195519ea8026Sopenharmony_ci bench_erase_sleep = erase_sleep*1.0e9; 195619ea8026Sopenharmony_ci break; 195719ea8026Sopenharmony_ci } 195819ea8026Sopenharmony_ci // done parsing 195919ea8026Sopenharmony_ci case -1: 196019ea8026Sopenharmony_ci goto getopt_done; 196119ea8026Sopenharmony_ci // unknown arg, getopt prints a message for us 196219ea8026Sopenharmony_ci default: 196319ea8026Sopenharmony_ci exit(-1); 196419ea8026Sopenharmony_ci } 196519ea8026Sopenharmony_ci } 196619ea8026Sopenharmony_cigetopt_done: ; 196719ea8026Sopenharmony_ci 196819ea8026Sopenharmony_ci if (argc > optind) { 196919ea8026Sopenharmony_ci // reset our bench identifier list 197019ea8026Sopenharmony_ci bench_ids = NULL; 197119ea8026Sopenharmony_ci bench_id_count = 0; 197219ea8026Sopenharmony_ci bench_id_capacity = 0; 197319ea8026Sopenharmony_ci } 197419ea8026Sopenharmony_ci 197519ea8026Sopenharmony_ci // parse bench identifier, if any, cannibalizing the arg in the process 197619ea8026Sopenharmony_ci for (; argc > optind; optind++) { 197719ea8026Sopenharmony_ci bench_define_t *defines = NULL; 197819ea8026Sopenharmony_ci size_t define_count = 0; 197919ea8026Sopenharmony_ci 198019ea8026Sopenharmony_ci // parse name, can be suite or case 198119ea8026Sopenharmony_ci char *name = argv[optind]; 198219ea8026Sopenharmony_ci char *defines_ = strchr(name, ':'); 198319ea8026Sopenharmony_ci if (defines_) { 198419ea8026Sopenharmony_ci *defines_ = '\0'; 198519ea8026Sopenharmony_ci defines_ += 1; 198619ea8026Sopenharmony_ci } 198719ea8026Sopenharmony_ci 198819ea8026Sopenharmony_ci // remove optional path and .toml suffix 198919ea8026Sopenharmony_ci char *slash = strrchr(name, '/'); 199019ea8026Sopenharmony_ci if (slash) { 199119ea8026Sopenharmony_ci name = slash+1; 199219ea8026Sopenharmony_ci } 199319ea8026Sopenharmony_ci 199419ea8026Sopenharmony_ci size_t name_len = strlen(name); 199519ea8026Sopenharmony_ci if (name_len > 5 && strcmp(&name[name_len-5], ".toml") == 0) { 199619ea8026Sopenharmony_ci name[name_len-5] = '\0'; 199719ea8026Sopenharmony_ci } 199819ea8026Sopenharmony_ci 199919ea8026Sopenharmony_ci if (defines_) { 200019ea8026Sopenharmony_ci // parse defines 200119ea8026Sopenharmony_ci while (true) { 200219ea8026Sopenharmony_ci char *parsed; 200319ea8026Sopenharmony_ci size_t d = leb16_parse(defines_, &parsed); 200419ea8026Sopenharmony_ci intmax_t v = leb16_parse(parsed, &parsed); 200519ea8026Sopenharmony_ci if (parsed == defines_) { 200619ea8026Sopenharmony_ci break; 200719ea8026Sopenharmony_ci } 200819ea8026Sopenharmony_ci defines_ = parsed; 200919ea8026Sopenharmony_ci 201019ea8026Sopenharmony_ci if (d >= define_count) { 201119ea8026Sopenharmony_ci // align to power of two to avoid any superlinear growth 201219ea8026Sopenharmony_ci size_t ncount = 1 << lfs_npw2(d+1); 201319ea8026Sopenharmony_ci defines = realloc(defines, 201419ea8026Sopenharmony_ci ncount*sizeof(bench_define_t)); 201519ea8026Sopenharmony_ci memset(defines+define_count, 0, 201619ea8026Sopenharmony_ci (ncount-define_count)*sizeof(bench_define_t)); 201719ea8026Sopenharmony_ci define_count = ncount; 201819ea8026Sopenharmony_ci } 201919ea8026Sopenharmony_ci defines[d] = BENCH_LIT(v); 202019ea8026Sopenharmony_ci } 202119ea8026Sopenharmony_ci } 202219ea8026Sopenharmony_ci 202319ea8026Sopenharmony_ci // append to identifier list 202419ea8026Sopenharmony_ci *(bench_id_t*)mappend( 202519ea8026Sopenharmony_ci (void**)&bench_ids, 202619ea8026Sopenharmony_ci sizeof(bench_id_t), 202719ea8026Sopenharmony_ci &bench_id_count, 202819ea8026Sopenharmony_ci &bench_id_capacity) = (bench_id_t){ 202919ea8026Sopenharmony_ci .name = name, 203019ea8026Sopenharmony_ci .defines = defines, 203119ea8026Sopenharmony_ci .define_count = define_count, 203219ea8026Sopenharmony_ci }; 203319ea8026Sopenharmony_ci } 203419ea8026Sopenharmony_ci 203519ea8026Sopenharmony_ci // do the thing 203619ea8026Sopenharmony_ci op(); 203719ea8026Sopenharmony_ci 203819ea8026Sopenharmony_ci // cleanup (need to be done for valgrind benching) 203919ea8026Sopenharmony_ci bench_define_cleanup(); 204019ea8026Sopenharmony_ci if (bench_overrides) { 204119ea8026Sopenharmony_ci for (size_t i = 0; i < bench_override_count; i++) { 204219ea8026Sopenharmony_ci free((void*)bench_overrides[i].defines); 204319ea8026Sopenharmony_ci } 204419ea8026Sopenharmony_ci free((void*)bench_overrides); 204519ea8026Sopenharmony_ci } 204619ea8026Sopenharmony_ci if (bench_geometry_capacity) { 204719ea8026Sopenharmony_ci free((void*)bench_geometries); 204819ea8026Sopenharmony_ci } 204919ea8026Sopenharmony_ci if (bench_id_capacity) { 205019ea8026Sopenharmony_ci for (size_t i = 0; i < bench_id_count; i++) { 205119ea8026Sopenharmony_ci free((void*)bench_ids[i].defines); 205219ea8026Sopenharmony_ci } 205319ea8026Sopenharmony_ci free((void*)bench_ids); 205419ea8026Sopenharmony_ci } 205519ea8026Sopenharmony_ci} 2056