-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
209 lines (173 loc) · 10.4 KB
/
Makefile
File metadata and controls
209 lines (173 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
.PHONY: test coverage doc format format-check lint clean bench bench-compare bench-compare-py bench-compare-py-label bench-all bench-compare-labels bench-coverage bench-compare-coverage bench-compare-py-coverage bench-all-coverage local-ci check-qmcpy-python
# ============================================================================
# Configuration and helpers
# ============================================================================
FORMATTER_PROJECT=devtools/formatter
DOC_DEPOT ?= $(if $(TMPDIR),$(TMPDIR),/tmp/)qmcju-doc-depot
QMCPY_PYTHON_AUTO := $(shell \
for py in python python3 "$(HOME)/miniconda3/bin/python" "$(HOME)/miniconda3/envs/qmcpy/bin/python" "$(HOME)/miniconda3/envs/qmcpy-leadership/bin/python"; do \
if { [ -x "$$py" ] || command -v "$$py" >/dev/null 2>&1; } && "$$py" -c "import qmcpy" >/dev/null 2>&1; then \
printf "%s" "$$py"; \
break; \
fi; \
done)
PYTHON ?= $(if $(QMCPY_PYTHON_AUTO),$(QMCPY_PYTHON_AUTO),python)
BENCH_COVERAGE ?= 0
JULIA_BENCH_COVERAGE_FLAG := $(if $(filter 1,$(BENCH_COVERAGE)),--code-coverage=user,)
define RUN_TIMED
@start=$$(date +%s); \
$(1); \
exit_code=$$?; \
end=$$(date +%s); \
elapsed=$$((end - start)); \
printf '\n[%s] total runtime: %ss\n' "$(2)" "$$elapsed"; \
exit $$exit_code
endef
# Allow `make bench gaus` / `make bench-compare gaus` / `make bench-compare-py gaus`
# as shorthand for `LABEL=gaus`. `make` treats `gaus` as an extra goal, so consume
# it explicitly.
ifneq ($(filter bench bench-compare bench-compare-py,$(firstword $(MAKECMDGOALS))),)
EXTRA_BENCH_GOALS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
ifneq ($(strip $(EXTRA_BENCH_GOALS)),)
LABEL ?= $(firstword $(EXTRA_BENCH_GOALS))
.PHONY: $(EXTRA_BENCH_GOALS)
$(EXTRA_BENCH_GOALS):
@:
endif
endif
# Allow `make bench-compare-labels a b` or `make bench-compare-labels a b out` as
# shorthand for `LABEL_A=a LABEL_B=b [OUT_LABEL=out]`.
ifneq ($(filter bench-compare-labels,$(firstword $(MAKECMDGOALS))),)
EXTRA_LABEL_COMPARE_GOALS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
ifneq ($(strip $(EXTRA_LABEL_COMPARE_GOALS)),)
LABEL_A ?= $(word 1,$(EXTRA_LABEL_COMPARE_GOALS))
LABEL_B ?= $(word 2,$(EXTRA_LABEL_COMPARE_GOALS))
OUT_LABEL ?= $(word 3,$(EXTRA_LABEL_COMPARE_GOALS))
.PHONY: $(EXTRA_LABEL_COMPARE_GOALS)
$(EXTRA_LABEL_COMPARE_GOALS):
@:
endif
endif
# ============================================================================
# Project maintenance and setup
# ============================================================================
# Update packages and resolve dependencies
update:
julia --project=. -e 'using Pkg; Pkg.update(); Pkg.resolve'
# Instantiate project dependencies (includes Plots and all other deps). Download what Manifest.toml says.
setup:
julia --project=. -e 'using Pkg; Pkg.instantiate()'
# Clean build artifacts
clean:
rm -rf docs/build
rm -rf *.jl.cov *.jl.*.cov *.jl.mem lcov.info
find src benchmark test -name '*.cov' -delete
# ============================================================================
# Testing and coverage
# ============================================================================
# Run all tests
test:
julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.test()'
# Run tests with Julia coverage instrumentation
coverage:
find src test -name '*.cov' -delete
rm -f lcov.info
julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.test(coverage=true)'
julia --project=. devtools/process_coverage.jl
find src test -name '*.cov' -delete
# Run specific test file
test-%:
julia --project=. -e 'include("test/$*.jl")'
# ============================================================================
# Documentation
# ============================================================================
# Build documentation
doc:
$(call RUN_TIMED,rm -rf docs/build && JULIA_DEPOT_PATH="$(DOC_DEPOT):$(HOME)/.julia" julia --project=docs -e 'using Pkg; Pkg.instantiate(); Pkg.resolve()' && JULIA_DEPOT_PATH="$(DOC_DEPOT):$(HOME)/.julia" julia --project=docs docs/make.jl,doc)
# ============================================================================
# Formatting
# ============================================================================
# Format code with JuliaFormatter (uses the repo .JuliaFormatter.toml for all paths)
format:
julia --project=$(FORMATTER_PROJECT) -e 'using Pkg; Pkg.instantiate(); using JuliaFormatter; format(["src/", "test/", "benchmark/"])'
# Check formatting (CI-friendly, fails if changes needed)
format-check:
julia --project=$(FORMATTER_PROJECT) -e 'using Pkg; Pkg.instantiate(); using JuliaFormatter; @assert format(["src/", "test/", "benchmark/"], overwrite=false)'
# ============================================================================
# Smoke checks and notebooks
# ============================================================================
# Run a quick smoke test
smoke:
julia --project=. -e 'using QMC; dd = Lattice(3; randomize=true); tm = Uniform(dd); f = Genz(tm; kind=:continuous); sc = CubQMCLatticeG(f; abs_tol=0.01); r = integrate(sc); println(r)'
# Run all demo notebooks (like Python's booktest)
notebook:
julia --project=. test/run_notebooks.jl
# Run a single notebook by name: make notebook-quickstart
notebook-%:
julia --project=. test/run_notebooks.jl $*
# ============================================================================
# Benchmarking
# ============================================================================
# Run the benchmark suite (uses its own environment in benchmark/, set up on first run)
# Override output label with: make bench LABEL=gaus or make bench gaus
# Saves results to benchmark/results/latest.json (default) or <LABEL>.json
bench:
$(call RUN_TIMED,BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/runbenchmarks.jl $(LABEL),bench)
check-qmcpy-python:
@$(PYTHON) -c "import qmcpy" >/dev/null 2>&1 || \
( echo "Configured PYTHON='$(PYTHON)' cannot import qmcpy."; \
echo "Use PYTHON=/path/to/python with qmcpy installed."; \
exit 1 )
# Compare the working tree against a baseline git revision (default: HEAD, i.e.
# the effect of uncommitted changes). Override with: make bench-compare REV=master
# Override output label with: make bench-compare LABEL=gaus or make bench-compare gaus
# Output: benchmark/results/compare_head.md (default) or compare_<LABEL>.md
# Ratio = reference (REV) time ÷ local time → < 1: local slower | > 1: local faster
REV ?= HEAD
LABEL ?=
bench-compare:
$(call RUN_TIMED,BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare.jl $(REV) $(LABEL),bench-compare)
# Side-by-side Julia vs QMCPy comparison.
# Runs both the Julia and QMCPy benchmark harnesses for the requested labels.
# Override output label with: make bench-compare-py LABEL=gaus or make bench-compare-py gaus
# Output: benchmark/results/compare_python.md (default) or compare_python_<LABEL>.md
# Ratio = Python time ÷ Julia time → < 1: local (Julia) slower | > 1: local (Julia) faster
# Override compared inputs with: make bench-compare-py JL_LABEL=foo PY_LABEL=bar
# If LABEL is set, it also becomes the default input label for both sides.
JL_LABEL ?= $(if $(LABEL),$(LABEL),latest)
PY_LABEL ?= $(JL_LABEL)
bench-compare-py: bench check-qmcpy-python
$(call RUN_TIMED,$(PYTHON) benchmark/benchmark_qmcpy.py $(PY_LABEL) && BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare_py.jl $(JL_LABEL) $(PY_LABEL) $(LABEL),bench-compare-py)
# Explicit labeled Julia-vs-QMCPy comparison flow.
# Usage: make bench-compare-py-label LABEL=base
bench-compare-py-label: check-qmcpy-python
$(call RUN_TIMED,BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/runbenchmarks.jl $(LABEL) && $(PYTHON) benchmark/benchmark_qmcpy.py $(LABEL) && BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare_py.jl $(LABEL) $(LABEL) $(LABEL),bench-compare-py-label)
# Run the labeled Julia-only comparison and Julia-vs-QMCPy comparison in one task.
# Usage: make bench-all LABEL=base
bench-all:
$(call RUN_TIMED,$(MAKE) bench-compare BENCH_COVERAGE=$(BENCH_COVERAGE) LABEL=$(LABEL) && $(MAKE) bench-compare-py BENCH_COVERAGE=$(BENCH_COVERAGE) LABEL=$(LABEL),bench-all)
# Run the benchmark suite with coverage enabled and produce an lcov report over
# both src/ and benchmark/ coverage files.
bench-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench BENCH_COVERAGE=1 && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-coverage)
# Run the Julia-vs-Julia comparison with coverage enabled and produce an lcov report.
bench-compare-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-compare BENCH_COVERAGE=1 REV=$(REV) LABEL=$(LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-compare-coverage)
# Run the Julia-vs-QMCPy comparison with coverage enabled and produce an lcov report.
bench-compare-py-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-compare-py BENCH_COVERAGE=1 LABEL=$(LABEL) JL_LABEL=$(JL_LABEL) PY_LABEL=$(PY_LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-compare-py-coverage)
# Run the full labeled benchmark workflow with coverage enabled and produce an lcov report.
bench-all-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-all BENCH_COVERAGE=1 LABEL=$(LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-all-coverage)
# Compare two saved Julia benchmark-result labels and decide which one is better.
# Usage: make bench-compare-labels LABEL_A=a LABEL_B=b [OUT_LABEL=report]
# or: make bench-compare-labels a b [report]
bench-compare-labels:
julia benchmark/compare_labels.jl $(LABEL_A) $(LABEL_B) $(OUT_LABEL)
# ============================================================================
# Combination of above targets
# ============================================================================
# Run the local full-check pipeline: format code, collect unit-test,
# then collect full benchmark. Pass LABEL=... through to the benchmark step.
local-ci:
$(call RUN_TIMED,$(MAKE) format && $(MAKE) test && $(MAKE) bench-all LABEL=$(LABEL),local-ci)