runners: Treat erase timing as strictly per-byte

Initial results with the new timing calculations looked weird. Turns
out different block sizes perform surprisingly when they all cost the
same!

Fortunately, erases are the one operation where per-byte vs per-op
timing doesn't really matter, so reverting to only per-byte timing
solves this problem. Now, erasing 2 4KiB blocks should take the same
time as 1 8KiB block, instead of twice as long.

---

Arguably, erase timing shouldn't be _strictly_ linear w.r.t. block size.
There's a reason denser storage usually ends up with larger block sizes
after all. But preventing the block size from messing with per-byte
timings is much more interesting from a filesystem design perspective.
It also matches the behavior of artificially increasing block size to
reduce block allocator pressure.

Unfortunately, this also raises concerns with read/prog timing when
varying geometry is involved... Should we stick to the per-byte timing
in such cases? Is there a better timing model out there without too much
additional complexity?
This commit is contained in:
Christopher Haster
2026-01-31 14:35:03 -06:00
parent 4405ad47e4
commit 2a72dd1700
+18 -8
View File
@@ -35,16 +35,21 @@
// FR=104 MHz, quad prog (9.6 ns * 8/4)
// => +~19 ns for bus (not read!)
//
// simple:
// readed=40ns/B fR=50 MHz, quad read (20 ns * 8/4)
// progged=1582ns/B tPP=0.4 ms, page=256 (0.4 ms / 256 + bus)
// erased=10986ns/B tSE=45 ms, sector=4096 (45 ms / 4096)
//
// less-simple:
// reads=0ns (no transaction cost)
// progs=400000ns tPP=0.4 ms, page=256
// erases=45000000ns tSE=45 ms, sector=4096
// erases=0ns (no transaction cost)
// readed=40ns/B fR=50 MHz, quad read (20 ns * 8/4)
// progged=1484ns/B tPP=0.4 ms (((4096/256)*0.4ms - 0.4ms)/4096 + bus)
// erased=0ns/B (no per-byte cost)
// erased=10986ns/B tSE=45 ms, sector=4096 (45 ms / 4096)
//
// note we always treat erases as per-byte to simplify benchmarking
// across different block sizes
//
#ifdef BENCH_SIMPLE
BENCH_DEFINE(READS_TIMING, 0 )
@@ -56,10 +61,10 @@
#else
BENCH_DEFINE(READS_TIMING, 0 )
BENCH_DEFINE(PROGS_TIMING, 400000 )
BENCH_DEFINE(ERASES_TIMING, 45000000 )
BENCH_DEFINE(ERASES_TIMING, 0 )
BENCH_DEFINE(READED_TIMING, 40 )
BENCH_DEFINE(PROGGED_TIMING, 1484 )
BENCH_DEFINE(ERASED_TIMING, 0 )
BENCH_DEFINE(ERASED_TIMING, 10986 )
#endif
#else
// default timings for NAND flash, based on w25n01gv:
@@ -68,16 +73,21 @@
// FR=104 MHz, quad read/prog (9.6 ns * 8/4)
// => +~19 ns for bus
//
// simple:
// readed=31ns/B tRD1=25 us, p=2048, s=512 (25 us / 2048 + bus)
// progged=141ns/B tPP=250 us, p=2048, s=512 (250 us / 2048 + bus)
// erased=15ns/B tBE=2 ms, block=131072 (2 ms / 131072)
//
// less-simple:
// reads=25000ns tRD1=25 us, p=2048, s=512
// progs=250000ns tPP=250 us, p=2048, s=512
// erases=2000000ns tBE=2 ms, block=131072
// erases=0ns (no transaction cost)
// readed=31ns/B tRD1=25 us (((131072/2048)*25us - 25us)/131072 + bus)
// progged=139ns/B tPP=250 us (((131072/2048)*250us - 250us)/131072 + bus)
// erased=0ns/B (no per-byte cost)
// erased=15ns/B tBE=2 ms, block=131072 (2 ms / 131072)
//
// note we always treat erases as per-byte to simplify benchmarking
// across different block sizes
//
#ifdef BENCH_SIMPLE
BENCH_DEFINE(READS_TIMING, 0 )
@@ -89,10 +99,10 @@
#else
BENCH_DEFINE(READS_TIMING, 25000 )
BENCH_DEFINE(PROGS_TIMING, 250000 )
BENCH_DEFINE(ERASES_TIMING, 2000000 )
BENCH_DEFINE(ERASES_TIMING, 0 )
BENCH_DEFINE(READED_TIMING, 31 )
BENCH_DEFINE(PROGGED_TIMING, 139 )
BENCH_DEFINE(ERASED_TIMING, 0 )
BENCH_DEFINE(ERASED_TIMING, 15 )
#endif
#endif
#ifndef BENCH_KIWIBD