Files
littlefs/Makefile
T
Christopher Haster b97c3b67c9 make: Fixed throughput calculation for litmus benchmarks
So, avg seems like a poor way to merge throughput results, at least for
bench_rbyd (avg create/delete throughputs were wildly different).

To fix this, changed make benchmarks and friends to a two step
calculation:

1. find max results: -fn='max(n)' -ft='float(bench_simtime)/1.0e9'
2. calculate throughput: -fthroughput='avg(float(n) / max(t, 1.0e-9))'

As a plus, this is probably more robust toward accidentally introducing
new by fields.

Note this does require two csv.py calls. csv.py doesn't support exprs
after folding as an intentional simplification (in theory it's always
possible to chain multiple csv.py calls together). In make this can be a
bit annoying since we need SHELL=/bin/bash for subprocess substitution
(for benchmarks-diff specifically), but that's not the end of the world.

--

Also changed -Si='min(enumerate())' -> -Si -Fi='min(enumerate())', in
case users override SUMMARYFLAGS.
2026-02-19 14:08:25 -06:00

782 lines
19 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
# 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_YES_STACK
endif
ifdef HEAP
TEST_CFLAGS += -DTEST_YES_HEAP
TEST_CFLAGS += -Wl,--wrap=malloc
TEST_CFLAGS += -Wl,--wrap=free
TEST_CFLAGS += -Wl,--wrap=realloc
endif
BENCH_CFLAGS += -Wno-unused-function
BENCH_CFLAGS += -Wno-format-overflow
ifndef NO_STACK
BENCH_CFLAGS += -DBENCH_YES_STACK
endif
ifndef NO_HEAP
BENCH_CFLAGS += -DBENCH_YES_HEAP
BENCH_CFLAGS += -Wl,--wrap=malloc
BENCH_CFLAGS += -Wl,--wrap=free
BENCH_CFLAGS += -Wl,--wrap=realloc
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
# 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: SHELL=/bin/bash
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: SHELL=/bin/bash
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: SHELL=/bin/bash
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: SHELL=/bin/bash
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: testmarks
testmarks: SUMMARYFLAGS+=-Si
testmarks: $(TEST_CSV)
$(strip ./scripts/csv.py $^ \
-bsuite \
-Fi='min(enumerate())' \
-fpassed=test_passed \
-fruntime=test_runtime \
$(SUMMARYFLAGS))
## Save the test results with TESTMARKS
.PHONY: testmarks-csv
testmarks-csv: $(BUILDDIR)/lfs3.test.csv
## Compare test results against a previous run
.PHONY: testmarks-diff
testmarks-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: testmarks-bottlenecks
testmarks-bottlenecks: SUMMARYFLAGS+=-Sruntime
testmarks-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: benchmarks
benchmarks: SUMMARYFLAGS+=-Si
benchmarks: SHELL=/bin/bash
benchmarks: $(BENCH_CSV)
$(strip ./scripts/csv.py \
<(./scripts/csv.py $^ \
-bprobe='%(case)s+%(probe)s' \
-Fi='min(enumerate())' \
-fn='max(n)' \
-ft='float(bench_simtime)/1.0e9' \
-o-) \
-bprobe \
-fn \
-ft \
-fthroughput='avg(float(n) / max(t, 1.0e-9))' \
$(SUMMARYFLAGS))
## Save the bench results
.PHONY: benchmarks-csv
benchmarks-csv: $(BUILDDIR)/lfs3.bench.csv
## Compare bench results against a previous run
.PHONY: benchmarks-diff
benchmarks-diff: SHELL=/bin/bash
benchmarks-diff: $(BENCH_CSV)
$(strip ./scripts/csv.py \
<(./scripts/csv.py $^ \
-bprobe='%(case)s+%(probe)s' \
-Fi='min(enumerate())' \
-fn='max(n)' \
-ft='float(bench_simtime)/1.0e9' \
-o-) \
-d <(./scripts/csv.py $(BUILDDIR)/lfs3.bench.csv \
-bprobe='%(case)s+%(probe)s' \
-Fi='min(enumerate())' \
-fn='max(n)' \
-ft='float(bench_simtime)/1.0e9' \
-o-) \
-bprobe \
-fthroughput='avg(float(n) / max(t, 1.0e-9))' \
$(SUMMARYFLAGS))
## Show which tests took the most time
.PHONY: benchmarks-bottlenecks
benchmarks-bottlenecks: SUMMARYFLAGS+=-Sruntime
benchmarks-bottlenecks: SHELL=/bin/bash
benchmarks-bottlenecks: $(BENCH_CSV)
$(strip ./scripts/csv.py \
<(./scripts/csv.py $^ \
-bprobe='%(case)s+%(probe)s' \
-Fi='min(enumerate())' \
-fn='max(n)' \
-ft='float(bench_simtime)/1.0e9' \
-fruntime='max(bench_runtime)' \
-o-) \
-bprobe \
-fn \
-ft \
-fruntime \
$(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)