238c2babe4
The litmus benches are really only intended for introspection/debugging/ cool plots/etc. They're interesting to poke around with and cover a wide range of littlefs's data-structures, but are not very rigorous. To make this more clear for new users, added a new litmus flag for benches: litmus = true This doesn't change anything about how the bench is run, but serves as a marker to hint that the bench is intended for non-rigorous benchmarking. --- In the makefile, litmus tests are disabled by default at runtime (--no-litmus). This is to limit `make bench` to benches that are useful for performance comparisons. With --no-litmus at runtime, the litmus benches are at least compiled into the bench_runner, which should hopefully encourage keeping them up to date with code changes. Eventually we should also run them in CI, but only to check for runtime errors. Unlike our tests, we're not really worried about compile time at the moment due to how few/small our benches are.
884 lines
22 KiB
Makefile
884 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
|
|
|
|
# default to not running litmus benches
|
|
ifndef BENCH_ALL
|
|
BENCHFLAGS += --no-litmus
|
|
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 $^ \
|
|
-Uprobe=stack,heap,usage \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-o-) \
|
|
-bprobe \
|
|
-Hprobe=bench+probe \
|
|
-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 $^ \
|
|
-Uprobe=stack,heap,usage \
|
|
-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 \
|
|
-Uprobe=stack,heap,usage \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-o-) \
|
|
-bprobe \
|
|
-Hprobe=bench+probe \
|
|
-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 $^ \
|
|
-Uprobe=stack,heap,usage \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Fi='min(enumerate())' \
|
|
-fn='max(n)' \
|
|
-ft='max(float(bench_simtime)/1.0e9)' \
|
|
-fruntime='max(bench_runtime)' \
|
|
-o-) \
|
|
-bprobe \
|
|
-Hprobe=bench+probe \
|
|
-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 $^ \
|
|
-Uprobe=stack,heap,usage \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Hprobe=bench+probe \
|
|
-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 $^ \
|
|
-Uprobe=stack,heap,usage \
|
|
-bprobe='%(case)s+%(probe)s' \
|
|
-Hprobe=bench+probe \
|
|
-Fi='min(enumerate())' \
|
|
-freaded="avg(saturate(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(saturate(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(saturate(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)
|