This is the code associated with the short paper "Simulation-Based Performance Characterization of Common NOR Flash File Systems".
This is a simulator for evaluating the performance of embedded flash file systems.
It models the interface to SPI NOR flash (see flash.hpp), with a DRAM region as the flash storage and read/write/erase functions for guarded access to the memory.
At this interface, the simulator collects statistics about read/write/erase operations and their sizes.
Together with timing information from flash chip datasheets, the latency for workloads can be estimated from the operation statistics.
Currently, streaming read and write as well as compression are available as workload benchmarks (see bench.hpp).
The available flash file systems are LittleFS, SPIFFS, NF2FS, and YAFFS2.
For stack trace generation, cpptrace is required (and with it libdwarf).
This is included in the devshell flake.nix and the Dockerfile.
After running a benchmark compiled with TRACE_OPS=1 (see flame_sampler.hpp), the corresponding flame graph can be created as follows:
flamegraph.pl stacks.folded > flamegraph.svgThis requires Brendan Gregg's flame graph scripts, which are also included in the devshell flake.nix.
Clone with submodules:
git clone --recursive git@github.com:2ck/flash-playground.gitSet up YAFFS (one time step):
pushd .
cd yaffs2
git apply ../yaffs_smaller_header.patch
cd direct
./handle_common.sh copy
popdBuild and run:
make run # *or*
make docker-runMany values can be adapted at runtime via environment variables, for example:
FS=YAFFS START_SIZE=4096 ITS=1 BENCH=compress make runThis will run the compress benchmark for YAFFS once with a file size of 4KiB.
The following table lists all supported environment variables:
| group | variable | default | description |
|---|---|---|---|
| flash | FLASH_SIZE |
MiB(128) |
total flash size in bytes |
FLASH_PAGE_SIZE |
256 |
size of largest write unit | |
FLASH_SECTOR_SIZE |
KiB(4) |
size of flash erase unit | |
FLASH_READ_GRANULARITY |
BYTE_WISE |
whether chunks < page_size can be read | |
FLASH_WRITE_GRANULARITY |
BYTE_WISE |
whether chunks < page_size can be written | |
| benchmarks | FS |
LFS |
one of "LFS", "SPIFFS", "NF2FS", "YAFFS" |
BENCH |
write |
one of "gc" (garbage collection), "mount_test" (just the FS mount process), "write"/"write_parallel" (write to one/multiple open files), "read", "compress" (read from one file and write half of each chunk to another), "open_close" | |
START_SIZE |
1024 |
size of first benchmark operation, n-th iteration will have size n * START_SIZE |
|
ITS |
64 |
iterations | |
PRE_FILL |
0 |
percentage of dirty pages to reach before benchmark | |
KEEP_FILES |
false |
whether to delete/unlink files used to pre-fill | |
CHUNK_SIZE |
page_size |
flash read/write chunk size | |
| misc. | PRINT_MALLOC_STATS |
false |
whether to output static and dynamic memory usage by FS |