c722bc08f5
Logging is one of those things that's very useful to keep around, but has a high-risk of stack/heap costs that shouldn't count towards any benchmarks (you can always disable logging). So, lets exclude them from stack/heap measurements. This could've been done by defining all of littlefs's LFS3_DEBUG/INFO/ WARN/ERROR macros, but intercepting printf directly is a bit less tedious. As a plus, we eliminate logging costs from any other filesystem we benchmark, without need to fiddle with everyone's logging APIs. --- Hmm. Actually, now that I've done a test run, these changes seem to have no effect. Which makes sense in hindsight: 1. For efficiencies sake, printf likely tries to allocate infrequently. Maybe only during the first call? And we print the bench id before entering the bench. 2. The way our stack measurements work, we only count them if we enter a bd op or call BENCH_STACK_PAUSE(). So any printfs encountered previously would have been ignored by our stack measurements. Still, better safe than sorry.
874 lines
22 KiB
Makefile
874 lines
22 KiB
Makefile
# overrideable build dir, default is in-place
|
|
BUILDDIR ?= .
|
|
# overrideable target, default to building a library
|
|
ifneq ($(wildcard test.c main.c),)
|
|
TARGET ?= $(BUILDDIR)/lfs3
|
|
else
|
|
TARGET ?= $(BUILDDIR)/liblfs3.a
|
|
endif
|
|
# process substitution my beloved
|
|
SHELL := /bin/bash
|
|
|
|
|
|
# find source files
|
|
SRC ?= $(filter-out %.t.c %.b.c %.a.c,$(wildcard *.c))
|
|
OBJ := $(SRC:%.c=$(BUILDDIR)/%.o)
|
|
DEP := $(SRC:%.c=$(BUILDDIR)/%.d)
|
|
ASM := $(SRC:%.c=$(BUILDDIR)/%.s)
|
|
CI := $(SRC:%.c=$(BUILDDIR)/%.ci)
|
|
GCDA := $(SRC:%.c=$(BUILDDIR)/%.t.a.gcda)
|
|
|
|
TESTS ?= $(wildcard tests/*.toml)
|
|
TEST_SRC ?= \
|
|
$(SRC) \
|
|
$(filter-out %.t.c %.b.c %.a.c,$(wildcard bd/*.c)) \
|
|
$(filter-out %.t.c %.b.c %.a.c,$(wildcard runners/test_*.c)) \
|
|
$(filter-out %.t.c %.b.c %.a.c,$(wildcard tests/*.c))
|
|
TEST_RUNNER ?= $(BUILDDIR)/runners/test_runner
|
|
TEST_C := \
|
|
$(TESTS:%.toml=$(BUILDDIR)/%.t.c) \
|
|
$(TEST_SRC:%.c=$(BUILDDIR)/%.t.c)
|
|
TEST_A := $(TEST_C:%.t.c=%.t.a.c)
|
|
TEST_OBJ := $(TEST_A:%.t.a.c=%.t.a.o)
|
|
TEST_DEP := $(TEST_A:%.t.a.c=%.t.a.d)
|
|
TEST_CI := $(TEST_A:%.t.a.c=%.t.a.ci)
|
|
TEST_GCNO := $(TEST_A:%.t.a.c=%.t.a.gcno)
|
|
TEST_GCDA := $(TEST_A:%.t.a.c=%.t.a.gcda)
|
|
TEST_PERF := $(TEST_RUNNER:%=%.perf)
|
|
TEST_TRACE := $(TEST_RUNNER:%=%.trace)
|
|
TEST_CSV := $(TEST_RUNNER:%=%.csv)
|
|
|
|
BENCHES ?= $(wildcard benches/*.toml)
|
|
BENCH_SRC ?= \
|
|
$(SRC) \
|
|
$(filter-out %.t.c %.b.c %.a.c,$(wildcard bd/*.c)) \
|
|
$(filter-out %.t.c %.b.c %.a.c,$(wildcard runners/bench_*.c)) \
|
|
$(filter-out %.t.c %.b.c %.a.c,$(wildcard benches/*.c))
|
|
BENCH_RUNNER ?= $(BUILDDIR)/runners/bench_runner
|
|
BENCH_C := \
|
|
$(BENCHES:%.toml=$(BUILDDIR)/%.b.c) \
|
|
$(BENCH_SRC:%.c=$(BUILDDIR)/%.b.c)
|
|
BENCH_A := $(BENCH_C:%.b.c=%.b.a.c)
|
|
BENCH_OBJ := $(BENCH_A:%.b.a.c=%.b.a.o)
|
|
BENCH_DEP := $(BENCH_A:%.b.a.c=%.b.a.d)
|
|
BENCH_CI := $(BENCH_A:%.b.a.c=%.b.a.ci)
|
|
BENCH_GCNO := $(BENCH_A:%.b.a.c=%.b.a.gcno)
|
|
BENCH_GCDA := $(BENCH_A:%.b.a.c=%.b.a.gcda)
|
|
BENCH_PERF := $(BENCH_RUNNER:%=%.perf)
|
|
BENCH_TRACE := $(BENCH_RUNNER:%=%.trace)
|
|
BENCH_CSV := $(BENCH_RUNNER:%=%.csv)
|
|
|
|
# overridable tools/flags
|
|
CC ?= gcc
|
|
AR ?= ar
|
|
SIZE ?= size
|
|
CTAGS ?= ctags
|
|
OBJDUMP ?= objdump
|
|
VALGRIND ?= valgrind
|
|
GDB ?= gdb
|
|
PERF ?= perf
|
|
PRETTYASSERTS ?= ./scripts/prettyasserts.py
|
|
|
|
CFLAGS += -fcallgraph-info=su
|
|
CFLAGS += -g3
|
|
CFLAGS += -I.
|
|
CFLAGS += -std=c99 -Wall -Wextra -pedantic
|
|
# labels are useful for debugging, in-function organization, etc
|
|
CFLAGS += -Wno-unused-label
|
|
# life's too short to not use this flag
|
|
CFLAGS += -Wno-unused-function
|
|
# compiler bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101854
|
|
CFLAGS += -Wno-stringop-overflow
|
|
CFLAGS += -ftrack-macro-expansion=0
|
|
ifdef DEBUG
|
|
CFLAGS += -O0
|
|
else
|
|
CFLAGS += -Os
|
|
endif
|
|
ifdef TRACE
|
|
CFLAGS += -DLFS3_YES_TRACE
|
|
endif
|
|
ifdef COVGEN
|
|
CFLAGS += --coverage
|
|
endif
|
|
ifdef PERFGEN
|
|
CFLAGS += -fno-omit-frame-pointer
|
|
endif
|
|
ifdef PERFBDGEN
|
|
CFLAGS += -fno-omit-frame-pointer
|
|
endif
|
|
|
|
# also forward all LFS3_* environment variables
|
|
CFLAGS += $(foreach d,$(filter LFS3_%,$(.VARIABLES)),-D$d=$($d))
|
|
|
|
TEST_CFLAGS += -Wno-unused-function
|
|
TEST_CFLAGS += -Wno-format-overflow
|
|
ifdef STACK
|
|
TEST_CFLAGS += -DTEST_STACK
|
|
TEST_CFLAGS += -Wl,--wrap=printf
|
|
TEST_CFLAGS += -Wl,--wrap=vprintf
|
|
endif
|
|
ifdef HEAP
|
|
TEST_CFLAGS += -DTEST_HEAP
|
|
TEST_CFLAGS += -Wl,--wrap=malloc
|
|
TEST_CFLAGS += -Wl,--wrap=free
|
|
TEST_CFLAGS += -Wl,--wrap=realloc
|
|
TEST_CFLAGS += -Wl,--wrap=printf
|
|
TEST_CFLAGS += -Wl,--wrap=vprintf
|
|
endif
|
|
|
|
BENCH_CFLAGS += -Wno-unused-function
|
|
BENCH_CFLAGS += -Wno-format-overflow
|
|
ifndef NO_STACK
|
|
BENCH_CFLAGS += -DBENCH_STACK
|
|
BENCH_CFLAGS += -Wl,--wrap=printf
|
|
BENCH_CFLAGS += -Wl,--wrap=vprintf
|
|
endif
|
|
ifndef NO_HEAP
|
|
BENCH_CFLAGS += -DBENCH_HEAP
|
|
BENCH_CFLAGS += -Wl,--wrap=malloc
|
|
BENCH_CFLAGS += -Wl,--wrap=free
|
|
BENCH_CFLAGS += -Wl,--wrap=realloc
|
|
BENCH_CFLAGS += -Wl,--wrap=printf
|
|
BENCH_CFLAGS += -Wl,--wrap=vprintf
|
|
endif
|
|
|
|
ifdef VERBOSE
|
|
CODEFLAGS += -v
|
|
DATAFLAGS += -v
|
|
STACKFLAGS += -v
|
|
CTXFLAGS += -v
|
|
STRUCTSFLAGS += -v
|
|
COVFLAGS += -v
|
|
PERFFLAGS += -v
|
|
PERFBDFLAGS += -v
|
|
endif
|
|
# forward -j flag
|
|
PERFFLAGS += $(filter -j%,$(MAKEFLAGS))
|
|
PERFBDFLAGS += $(filter -j%,$(MAKEFLAGS))
|
|
ifneq ($(OBJDUMP),objdump)
|
|
CODEFLAGS += --objdump-path="$(OBJDUMP)"
|
|
DATAFLAGS += --objdump-path="$(OBJDUMP)"
|
|
STACKFLAGS += --objdump-path="$(OBJDUMP)"
|
|
CTXFLAGS += --objdump-path="$(OBJDUMP)"
|
|
STRUCTSFLAGS += --objdump-path="$(OBJDUMP)"
|
|
PERFFLAGS += --objdump-path="$(OBJDUMP)"
|
|
PERFBDFLAGS += --objdump-path="$(OBJDUMP)"
|
|
endif
|
|
ifneq ($(PERF),perf)
|
|
PERFFLAGS += --perf-path="$(PERF)"
|
|
endif
|
|
|
|
TESTFLAGS += -b
|
|
BENCHFLAGS += -b
|
|
# forward -j flag
|
|
TESTFLAGS += $(filter -j%,$(MAKEFLAGS))
|
|
BENCHFLAGS += $(filter -j%,$(MAKEFLAGS))
|
|
ifdef PERFGEN
|
|
TESTFLAGS += -p$(TEST_PERF)
|
|
BENCHFLAGS += -p$(BENCH_PERF)
|
|
endif
|
|
ifdef PERFBDGEN
|
|
TESTFLAGS += -t$(TEST_TRACE) --trace-backtrace --trace-freq=100
|
|
BENCHFLAGS += -t$(BENCH_TRACE) --trace-backtrace --trace-freq=100
|
|
endif
|
|
ifdef TESTMARKS
|
|
TESTFLAGS += -o$(TEST_CSV)
|
|
endif
|
|
ifndef NO_BENCHMARKS
|
|
BENCHFLAGS += -o$(BENCH_CSV)
|
|
endif
|
|
ifdef VERBOSE
|
|
TESTFLAGS += -v
|
|
TESTCFLAGS += -v
|
|
BENCHFLAGS += -v
|
|
BENCHCFLAGS += -v
|
|
endif
|
|
ifdef EXEC
|
|
TESTFLAGS += --exec="$(EXEC)"
|
|
BENCHFLAGS += --exec="$(EXEC)"
|
|
endif
|
|
ifneq ($(GDB),gdb)
|
|
TESTFLAGS += --gdb-path="$(GDB)"
|
|
BENCHFLAGS += --gdb-path="$(GDB)"
|
|
endif
|
|
ifneq ($(VALGRIND),valgrind)
|
|
TESTFLAGS += --valgrind-path="$(VALGRIND)"
|
|
BENCHFLAGS += --valgrind-path="$(VALGRIND)"
|
|
endif
|
|
ifneq ($(PERF),perf)
|
|
TESTFLAGS += --perf-path="$(PERF)"
|
|
BENCHFLAGS += --perf-path="$(PERF)"
|
|
endif
|
|
|
|
# alternative bench geometries (defaults to NOR flash)
|
|
ifdef BENCH_NOR
|
|
BENCHFLAGS += -DDISK_GEOMETRY=0
|
|
endif
|
|
ifdef BENCH_NAND
|
|
BENCHFLAGS += -DDISK_GEOMETRY=1
|
|
endif
|
|
ifdef BENCH_PERBYTE
|
|
BENCHFLAGS += -DDISK_SIM=1
|
|
endif
|
|
|
|
# this is a bit of a hack, but we want to make sure the BUILDDIR
|
|
# directory structure is correct before we run any commands
|
|
ifneq ($(BUILDDIR),.)
|
|
$(if $(findstring n,$(MAKEFLAGS)),, $(shell mkdir -p \
|
|
$(BUILDDIR) \
|
|
$(addprefix $(BUILDDIR)/,$(dir \
|
|
$(SRC) \
|
|
$(TESTS) \
|
|
$(TEST_SRC) \
|
|
$(BENCHES) \
|
|
$(BENCH_SRC)))))
|
|
endif
|
|
|
|
|
|
# top-level commands
|
|
|
|
## Build littlefs
|
|
.PHONY: all build
|
|
all build: $(TARGET)
|
|
|
|
## Build assembly files
|
|
.PHONY: asm
|
|
asm: $(ASM)
|
|
|
|
## Find total section sizes
|
|
.PHONY: size
|
|
size: $(OBJ)
|
|
$(SIZE) -t $^
|
|
|
|
## Generate a ctags file
|
|
#
|
|
# run twice to only include prototypes in header files
|
|
.PHONY: tags ctags
|
|
tags ctags:
|
|
$(strip $(CTAGS) \
|
|
--totals --fields=+n --c-types=+p \
|
|
$(shell find -H -name '*.h'))
|
|
$(strip $(CTAGS) \
|
|
--totals --append --fields=+n \
|
|
$(SRC))
|
|
|
|
## Show this help text
|
|
.PHONY: help
|
|
help:
|
|
@$(strip awk '/^## / { \
|
|
sub(/^## /,""); \
|
|
getline rule; \
|
|
while (rule ~ /^(#|\.PHONY|ifdef|ifndef)/) getline rule; \
|
|
gsub(/:.*/, "", rule); \
|
|
if (length(rule) <= 21) { \
|
|
printf "%2s%-21s %s\n", "", rule, $$0; \
|
|
} else { \
|
|
printf "%2s%s\n", "", rule; \
|
|
printf "%24s%s\n", "", $$0; \
|
|
} \
|
|
}' $(MAKEFILE_LIST))
|
|
|
|
## Find the per-function code size
|
|
.PHONY: code
|
|
code: CODEFLAGS+=-S
|
|
code: $(OBJ)
|
|
./scripts/code.py $^ $(CODEFLAGS)
|
|
|
|
## Save the per-function code size
|
|
.PHONY: code-csv
|
|
code-csv: $(BUILDDIR)/lfs3.code.csv
|
|
|
|
## Compare per-function code size
|
|
.PHONY: code-diff
|
|
code-diff: $(OBJ)
|
|
./scripts/code.py $^ $(CODEFLAGS) -d $(BUILDDIR)/lfs3.code.csv
|
|
|
|
## Find the per-function data size
|
|
.PHONY: data
|
|
data: DATAFLAGS+=-S
|
|
data: $(OBJ)
|
|
./scripts/data.py $^ $(DATAFLAGS)
|
|
|
|
## Save the per-function data size
|
|
.PHONY: data-csv
|
|
data-csv: $(BUILDDIR)/lfs3.data.csv
|
|
|
|
## Compare per-function data size
|
|
.PHONY: data-diff
|
|
data-diff: $(OBJ)
|
|
./scripts/data.py $^ $(DATAFLAGS) -d $(BUILDDIR)/lfs3.data.csv
|
|
|
|
## Find the per-function stack usage
|
|
.PHONY: stack
|
|
stack: STACKFLAGS+=-S
|
|
stack: $(CI)
|
|
./scripts/stack.py $^ $(STACKFLAGS)
|
|
|
|
## Save the per-function stack usage
|
|
.PHONY: stack-csv
|
|
stack-csv: $(BUILDDIR)/lfs3.stack.csv
|
|
|
|
## Compare per-function stack usage
|
|
.PHONY: stack-diff
|
|
stack-diff: $(CI)
|
|
./scripts/stack.py $^ $(STACKFLAGS) -d $(BUILDDIR)/lfs3.stack.csv
|
|
|
|
## Find the per-function context
|
|
.PHONY: ctx
|
|
ctx: CTXFLAGS+=-S
|
|
ctx: $(OBJ)
|
|
./scripts/ctx.py $^ $(CTXFLAGS)
|
|
|
|
## Save the per-function context
|
|
.PHONY: ctx-csv
|
|
ctx-csv: $(BUILDDIR)/lfs3.ctx.csv
|
|
|
|
## Compare per-function context
|
|
.PHONY: ctx-diff
|
|
ctx-diff: $(CI)
|
|
./scripts/ctx.py $^ $(CTXFLAGS) -d $(BUILDDIR)/lfs3.ctx.csv
|
|
|
|
## Find function sizes
|
|
.PHONY: funcs
|
|
funcs: SUMMARYFLAGS+=-S
|
|
funcs: $(OBJ) $(CI)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/code.py $(OBJ) $(CODEFLAGS) -o-) \
|
|
<(./scripts/stack.py $(CI) $(STACKFLAGS) -o-) \
|
|
<(./scripts/ctx.py $(OBJ) $(CTXFLAGS) -o-) \
|
|
-bfunction \
|
|
-fcode=code_size \
|
|
-fstack='max(stack_limit)' \
|
|
-fctx='max(ctx_size)' \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Save function sizes
|
|
.PHONY: funcs-csv
|
|
funcs-csv: \
|
|
$(BUILDDIR)/lfs3.code.csv \
|
|
$(BUILDDIR)/lfs3.stack.csv \
|
|
$(BUILDDIR)/lfs3.ctx.csv
|
|
|
|
## Compare function sizes
|
|
.PHONY: funcs-diff
|
|
funcs-diff: $(OBJ) $(CI)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/code.py $(OBJ) $(CODEFLAGS) -o-) \
|
|
<(./scripts/stack.py $(CI) $(STACKFLAGS) -o-) \
|
|
<(./scripts/ctx.py $(OBJ) $(CTXFLAGS) -o-) \
|
|
-bfunction \
|
|
-fcode=code_size \
|
|
-fstack='max(stack_limit)' \
|
|
-fctx='max(ctx_size)' \
|
|
-d <(./scripts/csv.py \
|
|
$(BUILDDIR)/lfs3.code.csv \
|
|
$(BUILDDIR)/lfs3.stack.csv \
|
|
$(BUILDDIR)/lfs3.ctx.csv \
|
|
-fcode_size=code_size \
|
|
-fstack_limit='max(stack_limit)' \
|
|
-fctx_size='max(ctx_size)' \
|
|
-o-) \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Find struct sizes
|
|
.PHONY: structs
|
|
structs: STRUCTSFLAGS+=-S
|
|
structs: $(OBJ)
|
|
./scripts/structs.py $^ $(STRUCTSFLAGS)
|
|
|
|
## Save struct sizes
|
|
.PHONY: structs-csv
|
|
structs-csv: $(BUILDDIR)/lfs3.structs.csv
|
|
|
|
## Compare struct sizes
|
|
.PHONY: structs-diff
|
|
structs-diff: $(OBJ)
|
|
./scripts/structs.py $^ $(STRUCTSFLAGS) -d $(BUILDDIR)/lfs3.structs.csv
|
|
|
|
## Find line/branch coverage after a test run with COVGEN
|
|
.PHONY: cov
|
|
cov: COVFLAGS+=-s
|
|
cov: $(GCDA)
|
|
$(strip ./scripts/cov.py $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(COVFLAGS))
|
|
|
|
## Save line/branch coverage
|
|
.PHONY: cov-csv
|
|
cov-csv: $(BUILDDIR)/lfs3.cov.csv
|
|
|
|
## Compare line/branch coverage
|
|
.PHONY: cov-diff
|
|
cov-diff: $(GCDA)
|
|
$(strip ./scripts/cov.py $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(COVFLAGS) -d $(BUILDDIR)/lfs3.cov.csv)
|
|
|
|
## Find perf results after bench run with PERFGEN
|
|
.PHONY: perf
|
|
perf: PERFFLAGS+=-S
|
|
perf: $(BENCH_PERF)
|
|
$(strip ./scripts/perf.py $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(PERFFLAGS))
|
|
|
|
## Save perf results
|
|
.PHONY: perf-csv
|
|
perf-csv: $(BUILDDIR)/lfs3.perf.csv
|
|
|
|
## Compare perf results
|
|
.PHONY: perf-diff
|
|
perf-diff: $(BENCH_PERF)
|
|
$(strip ./scripts/perf.py $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(PERFFLAGS) -d $(BUILDDIR)/lfs3.perf.csv)
|
|
|
|
## Find perfbd results after a bench run with PERFBDGEN
|
|
.PHONY: perfbd
|
|
perfbd: PERFBDFLAGS+=-S
|
|
perfbd: $(BENCH_TRACE)
|
|
$(strip ./scripts/perfbd.py $(BENCH_RUNNER) $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(PERFBDFLAGS))
|
|
|
|
## Save perfbd results
|
|
.PHONY: perfbd-csv
|
|
perfbd-csv: $(BUILDDIR)/lfs3.perfbd.csv
|
|
|
|
## Compare perfbd results
|
|
.PHONY: perfbd-diff
|
|
perfbd-diff: $(BENCH_TRACE)
|
|
$(strip ./scripts/perfbd.py $(BENCH_RUNNER) $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(PERFBDFLAGS) -d $(BUILDDIR)/lfs3.perfbd.csv)
|
|
|
|
## Find a summary of compile-time sizes
|
|
.PHONY: summary sizes
|
|
summary sizes: $(OBJ) $(CI)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/code.py $(OBJ) $(CODEFLAGS) -o-) \
|
|
<(./scripts/data.py $(OBJ) $(DATAFLAGS) -o-) \
|
|
<(./scripts/stack.py $(CI) $(STACKFLAGS) -o-) \
|
|
<(./scripts/ctx.py $(OBJ) $(CTXFLAGS) -o-) \
|
|
-bfunction \
|
|
-fcode=code_size \
|
|
-fdata=data_size \
|
|
-fstack='max(stack_limit)' \
|
|
-fctx='max(ctx_size)' \
|
|
-Y $(SUMMARYFLAGS))
|
|
|
|
## Save compile-time sizes
|
|
.PHONY: summary-csv sizes-csv
|
|
summary-csv sizes-csv: \
|
|
$(BUILDDIR)/lfs3.code.csv \
|
|
$(BUILDDIR)/lfs3.data.csv \
|
|
$(BUILDDIR)/lfs3.stack.csv \
|
|
$(BUILDDIR)/lfs3.ctx.csv
|
|
|
|
## Compare compile-time sizes
|
|
.PHONY: summary-diff sizes-diff
|
|
summary-diff sizes-diff: $(OBJ) $(CI)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/csv.py \
|
|
<(./scripts/code.py $(OBJ) $(CODEFLAGS) -o-) \
|
|
<(./scripts/data.py $(OBJ) $(DATAFLAGS) -o-) \
|
|
<(./scripts/stack.py $(CI) $(STACKFLAGS) -o-) \
|
|
<(./scripts/ctx.py $(OBJ) $(CTXFLAGS) -o-) \
|
|
-bbuild=AFTER \
|
|
-fcode=code_size \
|
|
-fdata=data_size \
|
|
-fstack='max(stack_limit)' \
|
|
-fctx='max(ctx_size)' \
|
|
-o-) \
|
|
<(./scripts/csv.py \
|
|
$(BUILDDIR)/lfs3.code.csv \
|
|
$(BUILDDIR)/lfs3.data.csv \
|
|
$(BUILDDIR)/lfs3.stack.csv \
|
|
$(BUILDDIR)/lfs3.ctx.csv \
|
|
-bbuild=BEFORE \
|
|
-fcode=code_size \
|
|
-fdata=data_size \
|
|
-fstack='max(stack_limit)' \
|
|
-fctx='max(ctx_size)' \
|
|
-o-) \
|
|
-bbuild -cBEFORE -Q $(SUMMARYFLAGS))
|
|
|
|
|
|
## Generate a codemap svg
|
|
.PHONY: codemap
|
|
codemap: CODEMAPFLAGS+=-W1125 -H525 --dark
|
|
codemap: $(BUILDDIR)/lfs3.codemap.svg
|
|
|
|
## Generate a tiny codemap, where 1 pixel ~= 1 byte
|
|
.PHONY: codemap-tiny
|
|
codemap-tiny: CODEMAPFLAGS+=--dark
|
|
codemap-tiny: $(BUILDDIR)/lfs3.codemap_tiny.svg
|
|
|
|
|
|
## Build the test-runner
|
|
.PHONY: test-runner build-tests
|
|
test-runner build-tests: CFLAGS+=$(TEST_CFLAGS)
|
|
# note we remove some binary dependent files during compilation,
|
|
# otherwise it's way to easy to end up with outdated results
|
|
test-runner build-tests: $(TEST_RUNNER)
|
|
ifdef COVGEN
|
|
rm -f $(TEST_GCDA)
|
|
endif
|
|
ifdef PERFGEN
|
|
rm -f $(TEST_PERF)
|
|
endif
|
|
ifdef PERFBDGEN
|
|
rm -f $(TEST_TRACE)
|
|
endif
|
|
|
|
## Run the tests, -j enables parallel tests
|
|
.PHONY: test
|
|
test: test-runner
|
|
./scripts/test.py -R$(TEST_RUNNER) $(TESTFLAGS)
|
|
|
|
## List the tests
|
|
.PHONY: test-list list-tests
|
|
test-list list-tests: test-runner
|
|
./scripts/test.py -R$(TEST_RUNNER) $(TESTFLAGS) -l
|
|
|
|
## Summarize the test results
|
|
.PHONY: test-marks
|
|
test-marks: SUMMARYFLAGS+=-Si
|
|
test-marks: $(TEST_CSV)
|
|
$(strip ./scripts/csv.py $^ \
|
|
-bsuite \
|
|
-Fi='min(enumerate())' \
|
|
-fpassed=test_passed \
|
|
-fruntime=test_runtime \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Save the test results with TESTMARKS
|
|
.PHONY: test-marks-csv
|
|
test-marks-csv: $(BUILDDIR)/lfs3.test.csv
|
|
|
|
## Compare test results against a previous run
|
|
.PHONY: test-marks-diff
|
|
test-marks-diff: $(TEST_CSV)
|
|
$(strip ./scripts/csv.py $^ \
|
|
-bsuite \
|
|
-Fi='min(enumerate())' \
|
|
-fpassed=test_passed \
|
|
-fruntime=test_runtime \
|
|
$(SUMMARYFLAGS) -d $(BUILDDIR)/lfs3.test.csv)
|
|
|
|
## Show which tests took the most time
|
|
.PHONY: test-bottlenecks
|
|
test-bottlenecks: SUMMARYFLAGS+=-Sruntime
|
|
test-bottlenecks: $(TEST_CSV)
|
|
$(strip ./scripts/csv.py $^ \
|
|
-bcase \
|
|
-Fi='min(enumerate())' \
|
|
-fpassed=test_passed \
|
|
-fruntime=test_runtime \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Build the bench-runner
|
|
.PHONY: bench-runner build-benches
|
|
bench-runner build-benches: CFLAGS+=$(BENCH_CFLAGS)
|
|
# note we remove some binary dependent files during compilation,
|
|
# otherwise it's way to easy to end up with outdated results
|
|
bench-runner build-benches: $(BENCH_RUNNER)
|
|
ifdef COVGEN
|
|
rm -f $(BENCH_GCDA)
|
|
endif
|
|
ifdef PERFGEN
|
|
rm -f $(BENCH_PERF)
|
|
endif
|
|
ifdef PERFBDGEN
|
|
rm -f $(BENCH_TRACE)
|
|
endif
|
|
|
|
## Run the benches, -j enables parallel benches
|
|
.PHONY: bench
|
|
bench: bench-runner
|
|
./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS)
|
|
|
|
## List the benches
|
|
.PHONY: bench-list list-benches
|
|
bench-list list-benches: bench-runner
|
|
./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) -l
|
|
|
|
## Summarize the bench results
|
|
.PHONY: bench-marks
|
|
bench-marks: SUMMARYFLAGS+=-Si
|
|
bench-marks: $(BENCH_CSV)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/csv.py $^ \
|
|
-Dprobe=create,delete,fetch,lookup,write \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-o-) \
|
|
-bprobe \
|
|
-fn \
|
|
-ft \
|
|
-fthroughput='avg(float(n) / max(t, 1.0e-9))' \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Save the bench results
|
|
.PHONY: bench-marks-csv
|
|
bench-marks-csv: $(BUILDDIR)/lfs3.bench.csv
|
|
|
|
## Compare bench results against a previous run
|
|
.PHONY: bench-marks-diff
|
|
bench-marks-diff: $(BENCH_CSV)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/csv.py $^ \
|
|
-Dprobe=create,delete,fetch,lookup,write \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-o-) \
|
|
-d <(./scripts/csv.py $(BUILDDIR)/lfs3.bench.csv \
|
|
-Dprobe=create,delete,fetch,lookup,write \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-o-) \
|
|
-bprobe \
|
|
-fthroughput='avg(float(n) / max(t, 1.0e-9))' \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Show which benches took the most time
|
|
.PHONY: bench-bottlenecks
|
|
bench-bottlenecks: SUMMARYFLAGS+=-Sruntime
|
|
bench-bottlenecks: $(BENCH_CSV)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/csv.py $^ \
|
|
-Dprobe=create,delete,fetch,lookup,write \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-fruntime='max(bench_runtime)' \
|
|
-o-) \
|
|
-bprobe \
|
|
-fn \
|
|
-ft \
|
|
-fruntime \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Show the amount readed/progged/erased
|
|
.PHONY: bench-ops
|
|
bench-ops: SUMMARYFLAGS+=-Si
|
|
bench-ops: $(BENCH_CSV)
|
|
$(strip ./scripts/csv.py $^ \
|
|
-Dprobe=create,delete,fetch,lookup,write \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-freads='bench_reads' \
|
|
-fprogs='bench_progs' \
|
|
-ferases='bench_erases' \
|
|
-freaded='bench_readed' \
|
|
-fprogged='bench_progged' \
|
|
-ferased='bench_erased' \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Show average readed/progged/erased per width
|
|
.PHONY: bench-widths
|
|
bench-widths: SUMMARYFLAGS+=-Si
|
|
bench-widths: $(BENCH_CSV)
|
|
$(strip ./scripts/csv.py $^ \
|
|
-Dprobe=create,delete,fetch,lookup,write \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-freaded="avg(ffrac( \
|
|
float(bench_readed)/float(bench_reads), \
|
|
max(1, $$( \
|
|
./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) \
|
|
--list-implicit-defines \
|
|
| sed -n 's/^READ_WIDTH=\(.*\)/\1/p'))))" \
|
|
-fprogged="avg(ffrac( \
|
|
float(bench_progged)/float(bench_progs), \
|
|
max(1, $$( \
|
|
./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) \
|
|
--list-implicit-defines \
|
|
| sed -n 's/^PROG_WIDTH=\(.*\)/\1/p'))))" \
|
|
-ferased="avg(ffrac( \
|
|
float(bench_erased)/float(bench_erases), \
|
|
max(1, $$( \
|
|
./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) \
|
|
--list-implicit-defines \
|
|
| sed -n 's/^ERASE_WIDTH=\(.*\)/\1/p'))))" \
|
|
$(SUMMARYFLAGS))
|
|
|
|
## Show heap/stack/disk usage
|
|
.PHONY: bench-usage
|
|
bench-usage: SUMMARYFLAGS+=-Si
|
|
bench-usage: $(BENCH_CSV)
|
|
$(strip ./scripts/csv.py \
|
|
<(./scripts/csv.py $^ \
|
|
-Dprobe=stack \
|
|
-bcase \
|
|
-Fi='min(enumerate())' \
|
|
-fstack='max(bench_simtime)' \
|
|
-o-) \
|
|
<(./scripts/csv.py $^ \
|
|
-Dprobe=heap \
|
|
-bcase \
|
|
-Fi='min(enumerate())' \
|
|
-fheap='max(bench_simtime)' \
|
|
-o-) \
|
|
<(./scripts/csv.py $^ \
|
|
-Dprobe=usage \
|
|
-bcase \
|
|
-Fi='min(enumerate())' \
|
|
-fdisk='max(bench_simtime)' \
|
|
-o-) \
|
|
-bcase \
|
|
-fstack \
|
|
-fheap \
|
|
-fdisk \
|
|
$(SUMMARYFLAGS))
|
|
|
|
|
|
|
|
|
|
# low-level rules
|
|
-include $(DEP)
|
|
-include $(TEST_DEP)
|
|
-include $(BENCH_DEP)
|
|
.SUFFIXES:
|
|
.SECONDARY:
|
|
|
|
$(BUILDDIR)/lfs3: $(OBJ)
|
|
$(CC) $(CFLAGS) $^ $(LFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/liblfs3.a: $(OBJ)
|
|
$(AR) rcs $@ $^
|
|
|
|
$(BUILDDIR)/lfs3.code.csv: $(OBJ)
|
|
./scripts/code.py $^ $(CODEFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/lfs3.data.csv: $(OBJ)
|
|
./scripts/data.py $^ $(DATAFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/lfs3.stack.csv: $(CI)
|
|
./scripts/stack.py $^ $(STACKFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/lfs3.ctx.csv: $(OBJ)
|
|
./scripts/ctx.py $^ $(CTXFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/lfs3.structs.csv: $(OBJ)
|
|
./scripts/structs.py $^ $(STRUCTSFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/lfs3.cov.csv: $(GCDA)
|
|
$(strip ./scripts/cov.py $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(COVFLAGS) -o$@)
|
|
|
|
$(BUILDDIR)/lfs3.perf.csv: $(BENCH_PERF)
|
|
$(strip ./scripts/perf.py $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(PERFFLAGS) -o$@)
|
|
|
|
$(BUILDDIR)/lfs3.perfbd.csv: $(BENCH_TRACE)
|
|
$(strip ./scripts/perfbd.py $(BENCH_RUNNER) $^ \
|
|
$(patsubst %,-F%,$(SRC)) \
|
|
$(PERFBDFLAGS) -o$@)
|
|
|
|
$(BUILDDIR)/lfs3.codemap.svg: $(OBJ) $(CI)
|
|
$(strip ./scripts/codemapsvg.py $^ $(CODEMAPFLAGS) -o$@ \
|
|
&& ./scripts/codemap.py $^ --no-header)
|
|
|
|
$(BUILDDIR)/lfs3.codemap_tiny.svg: $(OBJ) $(CI)
|
|
$(strip ./scripts/codemapsvg.py $^ --tiny $(CODEMAPFLAGS) -o$@ \
|
|
&& ./scripts/codemap.py $^ --no-header)
|
|
|
|
$(BUILDDIR)/lfs3.test.csv: $(TEST_CSV)
|
|
cp $^ $@
|
|
|
|
$(BUILDDIR)/lfs3.bench.csv: $(BENCH_CSV)
|
|
cp $^ $@
|
|
|
|
$(BUILDDIR)/runners/test_runner: $(TEST_OBJ)
|
|
$(CC) $(CFLAGS) $^ $(LFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/runners/bench_runner: $(BENCH_OBJ)
|
|
$(CC) $(CFLAGS) $^ $(LFLAGS) -o$@
|
|
|
|
# our main build rule generates .o, .d, and .ci files, the latter
|
|
# used for stack analysis
|
|
$(BUILDDIR)/%.o $(BUILDDIR)/%.ci: %.c
|
|
$(CC) -c -MMD $(CFLAGS) $< -o $(BUILDDIR)/$*.o
|
|
|
|
$(BUILDDIR)/%.o $(BUILDDIR)/%.ci: $(BUILDDIR)/%.c
|
|
$(CC) -c -MMD $(CFLAGS) $< -o $(BUILDDIR)/$*.o
|
|
|
|
$(BUILDDIR)/%.s: %.c
|
|
$(CC) -S $(CFLAGS) $< -o$@
|
|
|
|
$(BUILDDIR)/%.s: $(BUILDDIR)/%.c
|
|
$(CC) -S $(CFLAGS) $< -o$@
|
|
|
|
$(BUILDDIR)/%.a.c: %.c
|
|
$(PRETTYASSERTS) -Plfs3_ $< -o$@
|
|
|
|
$(BUILDDIR)/%.a.c: $(BUILDDIR)/%.c
|
|
$(PRETTYASSERTS) -Plfs3_ $< -o$@
|
|
|
|
$(BUILDDIR)/%.t.c: %.toml
|
|
./scripts/test.py -c $< $(TESTCFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/%.t.c: %.c $(TESTS)
|
|
./scripts/test.py -c $(TESTS) -s $< $(TESTCFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/%.b.c: %.toml
|
|
./scripts/bench.py -c $< $(BENCHCFLAGS) -o$@
|
|
|
|
$(BUILDDIR)/%.b.c: %.c $(BENCHES)
|
|
./scripts/bench.py -c $(BENCHES) -s $< $(BENCHCFLAGS) -o$@
|
|
|
|
## Clean everything
|
|
.PHONY: clean
|
|
clean:
|
|
rm -f $(BUILDDIR)/lfs3
|
|
rm -f $(BUILDDIR)/liblfs3.a
|
|
rm -f $(BUILDDIR)/lfs3.code.csv
|
|
rm -f $(BUILDDIR)/lfs3.data.csv
|
|
rm -f $(BUILDDIR)/lfs3.stack.csv
|
|
rm -f $(BUILDDIR)/lfs3.ctx.csv
|
|
rm -f $(BUILDDIR)/lfs3.structs.csv
|
|
rm -f $(BUILDDIR)/lfs3.cov.csv
|
|
rm -f $(BUILDDIR)/lfs3.perf.csv
|
|
rm -f $(BUILDDIR)/lfs3.perfbd.csv
|
|
rm -f $(BUILDDIR)/lfs3.codemap.svg
|
|
rm -f $(BUILDDIR)/lfs3.codemap_tiny.svg
|
|
rm -f $(BUILDDIR)/lfs3.test.csv
|
|
rm -f $(BUILDDIR)/lfs3.bench.csv
|
|
rm -f $(OBJ)
|
|
rm -f $(DEP)
|
|
rm -f $(ASM)
|
|
rm -f $(CI)
|
|
rm -f $(TEST_RUNNER)
|
|
rm -f $(TEST_A)
|
|
rm -f $(TEST_C)
|
|
rm -f $(TEST_OBJ)
|
|
rm -f $(TEST_DEP)
|
|
rm -f $(TEST_CI)
|
|
rm -f $(TEST_GCNO)
|
|
rm -f $(TEST_GCDA)
|
|
rm -f $(TEST_PERF)
|
|
rm -f $(TEST_TRACE)
|
|
rm -f $(TEST_CSV)
|
|
rm -f $(BENCH_RUNNER)
|
|
rm -f $(BENCH_A)
|
|
rm -f $(BENCH_C)
|
|
rm -f $(BENCH_OBJ)
|
|
rm -f $(BENCH_DEP)
|
|
rm -f $(BENCH_CI)
|
|
rm -f $(BENCH_GCNO)
|
|
rm -f $(BENCH_GCDA)
|
|
rm -f $(BENCH_PERF)
|
|
rm -f $(BENCH_TRACE)
|
|
rm -f $(BENCH_CSV)
|