4405ad47e4
The main changes:
- Added TEST_DEFINES and BENCH_DEFINES to allow overriding the default
test/bench define header:
-DTEST_DEFINES=my_test_defines.h
Note these are VERY different from LFS_DEFINES upstream. They aren't a
typical header file, and are included multiple times with various
query macros.
It's hacky, but works surprisingly well.
Or maybe I'll just do anything to avoid having to write multiline
macros. Ugh, backslashes.
- Moved more logic into bench/test_defines.h, including everything
needed to integrate other filesystems out-of-tree.
This mostly meant moving all of the cfg initialization logic into its
own query macro (replacing the BENCH/TEST_CFG field macros).
But this also includes a bunch of small tweaks encountered while trying
to get external benchmarks running again.
The external benchmarks include several other filesystems (littlefs2,
SPIFFS, Yaffs2), and I'm hoping this injectable/queryable header thing
will do a good job at avoiding a maintenance headache. (At least a
better job than forking bench_runner.c, which was the previous
solution.)
192 lines
4.9 KiB
C
192 lines
4.9 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
|
|
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__, "")
|
|
|
|
|
|
// 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
|
|
|
|
|
|
// generated bench configurations
|
|
struct lfs3_cfg;
|
|
|
|
enum bench_flags {
|
|
BENCH_INTERNAL = 0x1,
|
|
};
|
|
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)
|
|
|
|
|
|
// 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_YES_STACK
|
|
// get the maximum/current stack usage for this run
|
|
size_t bench_stack(void);
|
|
__attribute__((noinline))
|
|
size_t bench_stack_current(void);
|
|
__attribute__((noinline))
|
|
void bench_stack_pause(void);
|
|
void bench_stack_resume(void);
|
|
|
|
#define BENCH_STACK() bench_stack()
|
|
#define BENCH_STACK_CURRENT() bench_stack_current()
|
|
#define BENCH_STACK_PAUSE() bench_stack_pause()
|
|
#define BENCH_STACK_RESUME() bench_stack_resume()
|
|
#endif
|
|
|
|
#ifdef BENCH_YES_HEAP
|
|
// get the maximum/current heap usage for this run
|
|
size_t bench_heap(void);
|
|
size_t bench_heap_current(void);
|
|
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() bench_heap()
|
|
#define BENCH_HEAP_CURRENT() bench_heap_current()
|
|
#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)
|
|
#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
|