f7dbaf7707
This turned out to be a bit tricky, and the scheme in bench_rbyd is broken. The core issue is that we don't have a distinction between physical and logical block sizes, so we can't use a block device configured for one geometry with a littlefs instance operating on a different geometry. For this and other reasons we should probably have two configuration variables in the future, but at the moment that is out of scope. The problem with the approach in bench_rbyd, which changes the lfs_config at runtime, is that this breaks emubd which also depends on lfs_config due to a leaky abstraction. This causes unnoticed memory corruption. --- To get something working, the tests now change the underlying BLOCK_SIZE test define before the tests are run. This starts the test with a block device configured with a large block_size. To keep this from breaking things the geometry definitions in the test and bench runners no longer use default dependent definitions, instead defining everything explicitly. With block_size being so large, this makes some of the emubd operations less performant, notably the --disk option for exposing block device state during testing. It would also be nice to use the copy-on-write backend of emubd for some of the permutation testing, but since it operates on a block-by-block basis, it doesn't really work when the block device is just one big block.
144 lines
4.4 KiB
C
144 lines
4.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
|
|
|
|
|
|
// override LFS_TRACE
|
|
void bench_trace(const char *fmt, ...);
|
|
|
|
#define LFS_TRACE_(fmt, ...) \
|
|
bench_trace("%s:%d:trace: " fmt "%s\n", \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
__VA_ARGS__)
|
|
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
|
|
#define LFS_EMUBD_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
|
|
|
|
// provide BENCH_START/BENCH_STOP macros
|
|
void bench_start(void);
|
|
void bench_stop(void);
|
|
|
|
#define BENCH_START() bench_start()
|
|
#define BENCH_STOP() bench_stop()
|
|
|
|
|
|
// note these are indirectly included in any generated files
|
|
#include "bd/lfs_emubd.h"
|
|
#include <stdio.h>
|
|
|
|
// give source a chance to define feature macros
|
|
#undef _FEATURES_H
|
|
#undef _STDIO_H
|
|
|
|
|
|
// generated bench configurations
|
|
struct lfs_config;
|
|
|
|
enum bench_flags {
|
|
BENCH_REENTRANT = 0x1,
|
|
};
|
|
typedef uint8_t bench_flags_t;
|
|
|
|
typedef struct bench_define {
|
|
intmax_t (*cb)(void *data);
|
|
void *data;
|
|
} bench_define_t;
|
|
|
|
struct bench_case {
|
|
const char *name;
|
|
const char *path;
|
|
bench_flags_t flags;
|
|
size_t permutations;
|
|
|
|
const bench_define_t *defines;
|
|
|
|
bool (*filter)(void);
|
|
void (*run)(struct lfs_config *cfg);
|
|
};
|
|
|
|
struct bench_suite {
|
|
const char *name;
|
|
const char *path;
|
|
bench_flags_t flags;
|
|
|
|
const char *const *define_names;
|
|
size_t define_count;
|
|
|
|
const struct bench_case *cases;
|
|
size_t case_count;
|
|
};
|
|
|
|
|
|
// deterministic prng for pseudo-randomness in benches
|
|
uint32_t bench_prng(uint32_t *state);
|
|
|
|
#define BENCH_PRNG(state) bench_prng(state)
|
|
|
|
|
|
// access generated bench defines
|
|
intmax_t bench_define(size_t define);
|
|
|
|
#define BENCH_DEFINE(i) bench_define(i)
|
|
|
|
// a few preconfigured defines that control how benches run
|
|
|
|
#define BENCH_IMPLICIT_DEFINE_COUNT 12
|
|
#define BENCH_GEOMETRY_DEFINE_COUNT 3
|
|
|
|
#define READ_SIZE_i 0
|
|
#define PROG_SIZE_i 1
|
|
#define BLOCK_SIZE_i 2
|
|
#define BLOCK_COUNT_i 3
|
|
#define DISK_SIZE_i 4
|
|
#define CACHE_SIZE_i 5
|
|
#define LOOKAHEAD_SIZE_i 6
|
|
#define BLOCK_CYCLES_i 7
|
|
#define ERASE_VALUE_i 8
|
|
#define ERASE_CYCLES_i 9
|
|
#define BADBLOCK_BEHAVIOR_i 10
|
|
#define POWERLOSS_BEHAVIOR_i 11
|
|
|
|
#define READ_SIZE bench_define(READ_SIZE_i)
|
|
#define PROG_SIZE bench_define(PROG_SIZE_i)
|
|
#define BLOCK_SIZE bench_define(BLOCK_SIZE_i)
|
|
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i)
|
|
#define DISK_SIZE bench_define(DISK_SIZE_i)
|
|
#define CACHE_SIZE bench_define(CACHE_SIZE_i)
|
|
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
|
|
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
|
|
#define ERASE_VALUE bench_define(ERASE_VALUE_i)
|
|
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i)
|
|
#define BADBLOCK_BEHAVIOR bench_define(BADBLOCK_BEHAVIOR_i)
|
|
#define POWERLOSS_BEHAVIOR bench_define(POWERLOSS_BEHAVIOR_i)
|
|
|
|
#define BENCH_IMPLICIT_DEFINES \
|
|
/* name value (overridable) */ \
|
|
BENCH_DEF(READ_SIZE, PROG_SIZE ) \
|
|
BENCH_DEF(PROG_SIZE, BLOCK_SIZE ) \
|
|
BENCH_DEF(BLOCK_SIZE, 0 ) \
|
|
BENCH_DEF(BLOCK_COUNT, DISK_SIZE/BLOCK_SIZE ) \
|
|
BENCH_DEF(DISK_SIZE, 1024*1024 ) \
|
|
BENCH_DEF(CACHE_SIZE, lfs_max(64, lfs_max(READ_SIZE, PROG_SIZE))) \
|
|
BENCH_DEF(LOOKAHEAD_SIZE, 16 ) \
|
|
BENCH_DEF(BLOCK_CYCLES, -1 ) \
|
|
BENCH_DEF(ERASE_VALUE, 0xff ) \
|
|
BENCH_DEF(ERASE_CYCLES, 0 ) \
|
|
BENCH_DEF(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR ) \
|
|
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP )
|
|
|
|
#define BENCH_GEOMETRIES \
|
|
/* name read_size prog_size block_size */ \
|
|
BENCH_GEO("default", 16, 16, 512 ) \
|
|
BENCH_GEO("eeprom", 1, 1, 512 ) \
|
|
BENCH_GEO("emmc", 512, 512, 512 ) \
|
|
BENCH_GEO("nor", 1, 1, 4096 ) \
|
|
BENCH_GEO("nand", 4096, 4096, 32768 )
|
|
|
|
|
|
#endif
|