Files
littlefs/runners/bench_runner.h
T
Christopher Haster 10e77d9177 runners: bench: Added BENCH_SIMTIME/SIMRESET/PAUSE/RESUME/etc
- BENCH_SIMTIME()   => lfs3_kiwibd_simtime()
- BENCH_SIMRESET()  => lfs3_kiwibd_simreset()
- BENCH_SIMPAUSE()  => lfs3_kiwibd_simpause()
- BENCH_SIMRESUME() => lfs3_kiwibd_simresume()
- BENCH_RESET()     => lfs3_kiwibd_simreset() + BENCH_STACK/HEAP_RESET()
- BENCH_PAUSE()     => lfs3_kiwibd_simpause() + BENCH_STACK/HEAP_PAUSE()
- BENCH_RESUME()    => lfs3_kiwibd_simresume() + BENCH_STACK/HEAP_RESUME()

This does two things:

1. Adds pause/resume counters to bd counters to make it easier to
   exclude operations from the current bench (potentially useful for
   seq+disk usage).

2. Exposes bd simtime operations as BENCH_* macros, to make it a bit
   easier to interact with simtime without tying all the benches to
   kiwibd. (Not that we'll ever probably not use kiwibd, but still).

Also adopted 32-bit counters for stack/heap pause state instead of a
32-bit stack. Not that either are at a risk of overflowing, but better
safe than sorry.
2026-03-09 22:54:49 -05:00

239 lines
6.4 KiB
C

/*
* Runner for littlefs benchmarks
*
* Copyright (c) 2022, The littlefs authors.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BENCH_RUNNER_H
#define BENCH_RUNNER_H
#define BENCH_STRINGIFY_(x) #x
#define BENCH_STRINGIFY(x) BENCH_STRINGIFY_(x)
// the default BENCH_DEFINES path can be overridden to add shims for
// other filesystems out-of-tree
//
// note this is an unusual header file! instead of being included once,
// BENCH_DEFINES is included several times with various "query macros"
// defined before inclusion:
//
// - BENCH_INCLUDE - common includes (optional)
// - BENCH_DEFINE(name, value) - name and default values for bench defines
// - BENCH_CFG[+_CFG] - struct lfs3_cfg definition
// - BENCH_BDCFG[+_CFG] - struct lfs3_*bd_cfg definition
//
#ifndef BENCH_DEFINES
#define BENCH_DEFINES runners/bench_defines.h
#endif
// default to using kiwibd for benches
#if !defined(BENCH_EMUBD) && !defined(BENCH_KIWIBD)
#define BENCH_KIWIBD
#endif
// ifdef macros for emubd vs kiwibd
#ifdef BENCH_EMUBD
#define BENCH_IFDEF_EMUBD(a, b) (a)
#else
#define BENCH_IFDEF_EMUBD(a, b) (b)
#endif
#ifdef BENCH_KIWIBD
#define BENCH_IFDEF_KIWIBD(a, b) (a)
#else
#define BENCH_IFDEF_KIWIBD(a, b) (b)
#endif
// override LFS3_TRACE
#ifndef LFS3_NO_TRACE
void bench_trace(const char *fmt, ...);
#define LFS3_TRACE_(fmt, ...) \
bench_trace("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS3_TRACE(...) LFS3_TRACE_(__VA_ARGS__, "")
#define LFS3_EMUBD_TRACE(...) LFS3_TRACE_(__VA_ARGS__, "")
#define LFS3_KIWIBD_TRACE(...) LFS3_TRACE_(__VA_ARGS__, "")
#else
#define LFS3_TRACE(...)
#define LFS3_EMUBD_TRACE(...)
#define LFS3_KIWIBD_TRACE(...)
#endif
// note these are indirectly included in any generated files
#define BENCH_INCLUDE
#include BENCH_STRINGIFY(BENCH_DEFINES)
#undef BENCH_INCLUDE
#ifndef BENCH_KIWIBD
#include "bd/lfs3_emubd.h"
#else
#include "bd/lfs3_kiwibd.h"
#endif
#include "lfs3_util.h"
#include <stdio.h>
#include <stdint.h>
// give source a chance to define feature macros
#undef _FEATURES_H
#undef _STDIO_H
// some common types
#ifndef BENCH_KIWIBD
typedef lfs3_emubd_io_t bench_io_t;
typedef lfs3_emubd_sio_t bench_sio_t;
typedef lfs3_emubd_ns_t bench_ns_t;
typedef lfs3_emubd_sns_t bench_sns_t;
#else
typedef lfs3_kiwibd_io_t bench_io_t;
typedef lfs3_kiwibd_sio_t bench_sio_t;
typedef lfs3_kiwibd_ns_t bench_ns_t;
typedef lfs3_kiwibd_sns_t bench_sns_t;
#endif
// generated bench configurations
struct lfs3_cfg;
enum bench_flags {
BENCH_INTERNAL = 0x1,
BENCH_LITMUS = 0x2,
};
typedef uint8_t bench_flags_t;
typedef struct bench_define {
const char *name;
intmax_t *define;
intmax_t (*cb)(void *data, size_t i);
void *data;
size_t permutations;
} bench_define_t;
struct bench_case {
const char *name;
const char *path;
bench_flags_t flags;
const bench_define_t *defines;
size_t permutations;
bool (*if_)(void);
void (*run)(const struct lfs3_cfg *cfg);
};
struct bench_suite {
const char *name;
const char *path;
bench_flags_t flags;
const bench_define_t *defines;
size_t define_count;
const struct bench_case *cases;
size_t case_count;
};
extern const struct bench_suite *const bench_suites[];
extern const size_t bench_suite_count;
// BENCH_START/BENCH_STOP macros measure readed/progged/erased bytes
// through emubd
void bench_start(const char *probe);
void bench_stop(const char *probe, uintmax_t n);
#define BENCH_START(probe) bench_start(probe)
#define BENCH_STOP(probe, n) bench_stop(probe, n)
// BENCH_RESULT/BENCH_FRESULT allow for explicit non-io measurements
void bench_result(const char *probe, uintmax_t n, uintmax_t result);
void bench_fresult(const char *probe, uintmax_t n, double result);
#define BENCH_RESULT(probe, n, result) bench_result(probe, n, result)
#define BENCH_FRESULT(probe, n, result) bench_fresult(probe, n, result)
// extra hooks to get the current simtime, pause readed/progged/erased
// counters, etc
bench_ns_t bench_simtime(void);
void bench_simreset(void);
void bench_simpause(void);
void bench_simresume(void);
void bench_reset(void);
void bench_pause(void);
void bench_resume(void);
#define BENCH_SIMTIME() bench_simtime()
#define BENCH_SIMRESET() bench_simreset()
#define BENCH_SIMPAUSE() bench_simpause()
#define BENCH_SIMRESUME() bench_simresume()
#define BENCH_RESET() bench_reset()
#define BENCH_PAUSE() bench_pause()
#define BENCH_RESUME() bench_resume()
// deterministic prng for pseudo-randomness in benches
uint32_t bench_prng(uint32_t *state);
#define BENCH_PRNG(state) bench_prng(state)
// generation of specific permutations of an array for exhaustive benching
size_t bench_factorial(size_t x);
void bench_permutation(size_t i, uint32_t *buffer, size_t size);
#define BENCH_FACTORIAL(x) bench_factorial(x)
#define BENCH_PERMUTATION(i, buffer, size) bench_permutation(i, buffer, size)
#ifdef BENCH_STACK
// get the maximum/current stack usage for this run
extern size_t bench_stack_watermark;
__attribute__((noinline)) size_t bench_stack_current(void);
void bench_stack_reset(void);
__attribute__((noinline)) void bench_stack_pause(void);
void bench_stack_resume(void);
#define BENCH_STACK_WATERMARK() bench_stack_watermark
#define BENCH_STACK_CURRENT() bench_stack_current()
#define BENCH_STACK_RESET() bench_stack_reset()
#define BENCH_STACK_PAUSE() bench_stack_pause()
#define BENCH_STACK_RESUME() bench_stack_resume()
#else
// stubs if not measuring stack
#define BENCH_STACK_RESET()
#define BENCH_STACK_PAUSE()
#define BENCH_STACK_RESUME()
#endif
#ifdef BENCH_HEAP
// get the maximum/current heap usage for this run
extern size_t bench_heap_watermark;
extern size_t bench_heap_current;
void bench_heap_pause(void);
void bench_heap_resume(void);
void bench_heap_inc(size_t size);
void bench_heap_dec(size_t size);
#define BENCH_HEAP_WATERMARK() bench_heap_watermark
#define BENCH_HEAP_CURRENT() bench_heap_current
#define BENCH_HEAP_RESET() bench_heap_reset()
#define BENCH_HEAP_PAUSE() bench_heap_pause()
#define BENCH_HEAP_RESUME() bench_heap_resume()
#define BENCH_HEAP_INC(size) bench_heap_inc(size)
#define BENCH_HEAP_DEC(size) bench_heap_dec(size)
#else
// stubs if not measuring heap
#define BENCH_HEAP_RESET()
#define BENCH_HEAP_PAUSE()
#define BENCH_HEAP_RESUME()
#define BENCH_HEAP_INC(size)
#define BENCH_HEAP_DEC(size)
#endif
// declare implicit defines as global intmax_ts
#define BENCH_DEFINE(k, v) \
extern intmax_t k;
#include BENCH_STRINGIFY(BENCH_DEFINES)
#undef BENCH_DEFINE
#endif