bench/bench.c (`make bench`) measures create/read/stat/readdir/unlink/
mkdir on mem, dir, and raw fs; large sequential I/O; random-access pack
reads via mmap vs raw fs; compaction throughput; and 8-thread
concurrent mixed workloads. Results from one full run, with honest
analysis (what each "raw fs" vs "raw+fsync" vs "dir" label actually
measures, so they aren't misread as interchangeable), are in BENCH.md.
The benchmark surfaced a real, quantitatively-confirmed finding, not
just favorable numbers: bulk sequential create/unlink on mem/dir is
O(n^2) in file count (~9-22x slower than raw fs at N=20,000), because
every structural write copies the entire snapshot entry array before
publishing it (Section 5.3). concept.md itself names the exact trigger
condition for reconsidering this ("a persistent structurally-shared
tree structure is not required until this assumption is empirically
violated") — this benchmark is that violation, measured rather than
hypothesized: mkdir at N=4,000 vs create at N=20,000 (same mechanism,
5x the N) shows a 28.4x slowdown, matching the O(n^2) prediction (25x)
far better than O(n) (5x).
Also found: dir-backend stat() costs ~2x raw stat() (open+fstat vs one
syscall, the direct cost of openat2 containment on the metadata path);
mem-backed large writes lose to raw fs above ~16MB (Section 5.7's
buffer-growth discipline re-copies prior writes on every capacity
doubling, the price of never exposing a reader to a freed buffer).
Recorded the O(n^2) finding in CLAUDE.md's new "Known performance
characteristics" section, per the same pattern used for the
reclaim_gate use-after-free discovery, since it's exactly the kind of
fact that would otherwise have to be rediscovered by benchmarking
again from scratch. Linked from README and CONTRIBUTING.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UqJpkdJ6Njnt1pw3CbghzB
80 lines
2.2 KiB
Makefile
80 lines
2.2 KiB
Makefile
# Makefile — PackFS
|
|
#
|
|
# Builds the static and shared library from src/, plus the test binaries
|
|
# under tests/. See CLAUDE.md for the project's static-linking constraint
|
|
# (Section 11.1 of concept.md): the core here has zero required
|
|
# third-party dependencies; it links only against the platform C library,
|
|
# pthread, and (on Linux) direct kernel syscalls for openat2/Landlock.
|
|
|
|
CC ?= cc
|
|
AR ?= ar
|
|
PREFIX ?= /usr/local
|
|
|
|
CFLAGS ?= -std=c11 -Wall -Wextra -Wpedantic -O2 -g -fPIC
|
|
CFLAGS += -Iinclude -Isrc -D_GNU_SOURCE
|
|
LDLIBS := -lpthread
|
|
|
|
SRC := $(wildcard src/*.c)
|
|
OBJ := $(SRC:.c=.o)
|
|
|
|
STATIC_LIB := libpackfs.a
|
|
SONAME := libpackfs.so.0
|
|
SHARED_LIB := libpackfs.so
|
|
|
|
TEST_SRC := $(wildcard tests/test_*.c)
|
|
TEST_BIN := $(TEST_SRC:tests/%.c=build/%)
|
|
|
|
.PHONY: all static shared test demo bench clean install uninstall
|
|
|
|
all: static shared
|
|
|
|
static: $(STATIC_LIB)
|
|
|
|
shared: $(SHARED_LIB)
|
|
|
|
$(STATIC_LIB): $(OBJ)
|
|
$(AR) rcs $@ $(OBJ)
|
|
|
|
$(SHARED_LIB): $(OBJ)
|
|
$(CC) -shared -Wl,-soname,$(SONAME) -o $(SONAME) $(OBJ) $(LDLIBS)
|
|
ln -sf $(SONAME) $(SHARED_LIB)
|
|
|
|
%.o: %.c src/internal.h include/packfs.h
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
|
|
build:
|
|
mkdir -p build
|
|
|
|
build/%: tests/%.c $(STATIC_LIB) | build
|
|
$(CC) $(CFLAGS) $< $(STATIC_LIB) $(LDLIBS) -o $@
|
|
|
|
test: $(TEST_BIN)
|
|
@set -e; for t in $(TEST_BIN); do echo "-- $$t --"; $$t; done
|
|
|
|
build/packfs_demo: examples/demo.c $(STATIC_LIB) | build
|
|
$(CC) $(CFLAGS) $< $(STATIC_LIB) $(LDLIBS) -o $@
|
|
|
|
demo: build/packfs_demo
|
|
./build/packfs_demo
|
|
|
|
build/packfs_bench: bench/bench.c $(STATIC_LIB) | build
|
|
$(CC) $(CFLAGS) $< $(STATIC_LIB) $(LDLIBS) -o $@
|
|
|
|
bench: build/packfs_bench
|
|
./build/packfs_bench
|
|
|
|
clean:
|
|
rm -f src/*.o $(STATIC_LIB) $(SHARED_LIB) $(SONAME)
|
|
rm -rf build
|
|
|
|
install: static shared
|
|
install -d $(DESTDIR)$(PREFIX)/lib $(DESTDIR)$(PREFIX)/include
|
|
install -m 644 $(STATIC_LIB) $(DESTDIR)$(PREFIX)/lib/
|
|
install -m 755 $(SONAME) $(DESTDIR)$(PREFIX)/lib/
|
|
ln -sf $(SONAME) $(DESTDIR)$(PREFIX)/lib/$(SHARED_LIB)
|
|
install -m 644 include/packfs.h $(DESTDIR)$(PREFIX)/include/
|
|
|
|
uninstall:
|
|
rm -f $(DESTDIR)$(PREFIX)/lib/$(STATIC_LIB) $(DESTDIR)$(PREFIX)/lib/$(SONAME) $(DESTDIR)$(PREFIX)/lib/$(SHARED_LIB)
|
|
rm -f $(DESTDIR)$(PREFIX)/include/packfs.h
|