204 lines
7.0 KiB
Makefile
204 lines
7.0 KiB
Makefile
# Makefile for the project.
|
|
# Provides targets for building, running, benchmarking, testing, and visualization.
|
|
#
|
|
# Main commands:
|
|
# make run run the simulation, producing a CSV file
|
|
# containing pedestrian states at each iteration
|
|
# make video generate a video of the simulation
|
|
# make run-bench run benchmark measurements
|
|
# make test run all unit tests
|
|
#
|
|
# Default parameters can be overridden from the shell, as follows:
|
|
# (parameters can be provided selectively and in any order)
|
|
#
|
|
# make run N_P=<num_ped> N_ITER=<num_iter> CSV=<out.csv>
|
|
# make video N_P=<num_ped> N_ITER=<num_iter> CSV=<out.csv> MP4=<video.mp4>
|
|
# make run-bench N_P=<num_ped> N_ITER=<num_iter>
|
|
|
|
|
|
# Select the C++ compiler.
|
|
# Prefer g++ when available, otherwise fall back to clang++.
|
|
CXX := $(shell command -v g++ || command -v clang++)
|
|
|
|
ifeq ($(CXX),)
|
|
$(error No C++ compiler found. Please install g++ or clang++)
|
|
endif
|
|
|
|
ARCH := $(shell uname -m)
|
|
|
|
# Prepend sudo on ARM machines when benchmarking.
|
|
# This is needed to access the PMU performance counters.
|
|
ifeq ($(ARCH),arm64)
|
|
SUDO_BENCH := sudo
|
|
else ifeq ($(ARCH),aarch64)
|
|
SUDO_BENCH := sudo
|
|
else
|
|
SUDO_BENCH :=
|
|
endif
|
|
|
|
# Compiler flags:
|
|
# -O3 enable high-level optimization
|
|
# -march=native optimize for the current machine
|
|
# -std=c++23 use the C++23 standard
|
|
# -Wall -Wextra enable useful warnings
|
|
# -flto enable link-time optimization across .cpp files, allowing
|
|
# cross-file optimizations such as function inlining
|
|
CXXFLAGS := -O3 -march=native -std=c++23 -Wall -Wextra -flto
|
|
|
|
VARIANT ?= baseline
|
|
|
|
# sleef is only needed for the avx512 variant (used by SLEEF intrinsics there)
|
|
ifeq ($(ARCH),x86_64)
|
|
ifneq ($(filter avx512_%,$(VARIANT)),)
|
|
CXXFLAGS += -lsleef
|
|
endif
|
|
endif
|
|
|
|
VARIANT_SRC := ./variants/variant_$(VARIANT).cpp
|
|
|
|
ifneq ($(filter float_%,$(VARIANT)),)
|
|
MAIN_SRC := main-float.cpp
|
|
else
|
|
MAIN_SRC := main.cpp
|
|
endif
|
|
|
|
SRC := $(MAIN_SRC) $(VARIANT_SRC)
|
|
HEADERS := ./headers/board.hpp ./headers/pedestrian.hpp ./headers/vector2d.hpp ./headers/constants.hpp ./headers/util.hpp
|
|
|
|
TEST_SRC := ./tests/test_vector2d.cpp ./tests/test_board.cpp ./tests/test_forces.cpp $(VARIANT_SRC)
|
|
TEST_TARGET := run_tests
|
|
TEST_LIBS := -lgtest -lgtest_main -pthread
|
|
|
|
TARGET := main_$(VARIANT)
|
|
|
|
|
|
# Default simulation parameters and output files.
|
|
# These can be overridden from the make command line; see examples above.
|
|
N_P ?= 60 # Default number of pedestrians.
|
|
N_ITER ?= 4000 # Default number of simulation iterations.
|
|
CSV ?= positions.csv # Default CSV output file.
|
|
MP4 ?= simulation.mp4 # Default visualization video output file.
|
|
|
|
# Enable/disable non-reproducible random seeding.
|
|
# Default: RANDOM_SEED=0 uses the fixed seed for reproducibility.
|
|
# Use RANDOM_SEED=1 to seed from std::random_device.
|
|
RANDOM_SEED ?= 0
|
|
|
|
# flopcounter enabled/disabled, no impact on runtime when running with 0
|
|
# default = 0 = disabled
|
|
# 1 = enabled
|
|
# if set to 0 --> compiler will swap all function calls with ((void)0)
|
|
# using -O3 will remove all ((void)0)
|
|
FLOPCOUNT ?= 0
|
|
CXXFLAGS += -DFLOPCOUNT=$(FLOPCOUNT)
|
|
|
|
# Pass random-seeding mode to the C++ code.
|
|
CXXFLAGS += -DRANDOM_SEED=$(RANDOM_SEED)
|
|
|
|
# Roofline benchmarcking mode enabled/disabled
|
|
# default = 0 = disabled (hot cache, for normal performance plot measurments)
|
|
# 1 = enabled (cold cache, for roofline plot measurements)
|
|
ROOFLINE ?= 0
|
|
CXXFLAGS += -DROOFLINE=$(ROOFLINE)
|
|
|
|
# Benchmark suite parameters.
|
|
BENCH_SIZES ?= 50 100 200 500 1000
|
|
BENCH_ITER ?= 1000
|
|
|
|
# Verification parameters
|
|
|
|
ifneq ($(filter float_%,$(VARIANT)),)
|
|
# Float verify uses a short horizon (500 iters). The simulation is chaotic - a 1-ULP perturbation
|
|
# amplifies by ~exp(t/200) - so floats can't hold bit-equality across variants over 4000 iters
|
|
# no matter what we do (different layouts -> different FMA placements -> 1-ULP drift -> meters by t=4000).
|
|
# At 500 iters the amplifier is still small: AVX2 variants drift max ~4mm vs the scalar reference,
|
|
# well under 1cm, and real bugs still show as O(m) errors. 4000 iters drifts to meters even when
|
|
# the variant is correct, so that horizon is useless for verify.
|
|
REFERENCE_N_ITER ?= 500
|
|
REFERENCE_CSV ?= reference/baseline_float_n60_i500.csv
|
|
else
|
|
REFERENCE_N_ITER ?= 4000
|
|
REFERENCE_CSV ?= reference/baseline_n60_i4000.csv
|
|
endif
|
|
|
|
REFERENCE_N_P ?= 60
|
|
VERIFY_CSV := verify_$(VARIANT).csv
|
|
|
|
.PHONY: all main run bench run-bench bench-suite video asm test clean clean-all verify
|
|
|
|
all: main
|
|
|
|
# make main : compile the main executable with benchmarking disabled.
|
|
main: clean
|
|
$(CXX) $(SRC) -o $(TARGET) $(CXXFLAGS)
|
|
|
|
# make run : compile the code and run the simulation without generating a video.
|
|
run: main
|
|
./$(TARGET) $(N_P) $(N_ITER) $(CSV)
|
|
|
|
# make verify # sanity check (baseline vs reference)
|
|
# make verify VARIANT=v1_cutoff # check a specific variant
|
|
verify: main
|
|
./$(TARGET) $(REFERENCE_N_P) $(REFERENCE_N_ITER) $(VERIFY_CSV)
|
|
@if python3 ./scripts/verify.py $(REFERENCE_CSV) $(VERIFY_CSV); then \
|
|
echo "PASS: variant '$(VARIANT)' matches $(REFERENCE_CSV)"; \
|
|
rm -f $(VERIFY_CSV); \
|
|
else \
|
|
echo "FAIL: variant '$(VARIANT)' differs from $(REFERENCE_CSV) (kept $(VERIFY_CSV) for inspection)"; \
|
|
exit 1; \
|
|
fi
|
|
|
|
# make bench : compile the main executable with benchmarking enabled.
|
|
bench: CXXFLAGS += -DBENCHMARK=1
|
|
bench: clean
|
|
$(SUDO_BENCH) $(CXX) $(SRC) -o $(TARGET) $(CXXFLAGS)
|
|
|
|
# make run-bench : compile and run benchmark measurements.
|
|
run-bench: bench
|
|
$(SUDO_BENCH) ./$(TARGET) $(N_P) $(N_ITER)
|
|
|
|
# make bench-suite : compile once and run benchmarks across multiple pedestrian counts.
|
|
# Results are printed to stdout; redirect to a file to save them.
|
|
# make bench-suite > benchmarks/baseline.txt
|
|
# make bench-suite VARIANT=v1_cutoff BENCH_SIZES="100 500 1000" > benchmarks/v1_cutoff.txt
|
|
bench-suite: bench
|
|
@for n in $(BENCH_SIZES); do \
|
|
echo "=== N_P=$$n N_ITER=$(BENCH_ITER) ==="; \
|
|
$(SUDO_BENCH) ./$(TARGET) $$n $(BENCH_ITER); \
|
|
echo ""; \
|
|
done
|
|
|
|
# make video : compile the code, run the simulation, and generate the video.
|
|
video: run
|
|
python ./scripts/visualization.py $(CSV) $(MP4)
|
|
|
|
# make test : compile and run all unit tests.
|
|
test: clean
|
|
$(CXX) $(TEST_SRC) $(TEST_LIBS) -o $(TEST_TARGET) $(CXXFLAGS)
|
|
./$(TEST_TARGET)
|
|
|
|
# make asm : compile and generate assembly files.
|
|
|
|
ASM_CPP_SRCS := main.cpp main-float.cpp $(VARIANT_SRC)
|
|
ASM_HPP_SRCS := ./headers/util.hpp
|
|
ASM_SRCS := $(ASM_CPP_SRCS) $(ASM_HPP_SRCS)
|
|
|
|
ASM_TARGETS := $(patsubst %.cpp,%.s,$(patsubst %.hpp,%.s,$(ASM_SRCS)))
|
|
|
|
asm: clean
|
|
$(foreach src,$(ASM_CPP_SRCS),$(CXX) -S $(src) -o $(src:.cpp=.s) $(CXXFLAGS); )
|
|
$(foreach src,$(ASM_HPP_SRCS),$(CXX) -x c++ -S $(src) -o $(src:.hpp=.s) $(CXXFLAGS); )
|
|
|
|
|
|
%.s: %.cpp $(HEADERS)
|
|
$(CXX) -S $< -o $@ $(CXXFLAGS)
|
|
|
|
# make clean : delete generated files from previous builds.
|
|
clean:
|
|
rm -f main_* $(SIZES_TARGET) $(TEST_TARGET) *.o *.s variants/*.s variants/*.o headers/*.s headers/*.o
|
|
|
|
# make clean-all : delete all generated files from previous builds and runs.
|
|
# WARNING: this deletes all *.csv and *.mp4 files in this directory.
|
|
# Move any output files you want to keep to another directory before running it.
|
|
clean-all: clean
|
|
rm -f *.csv *.mp4
|