Skip to content

Commit cd81b11

Browse files
committed
feat(build): strengthen graph execution and caching
1 parent 7a27984 commit cd81b11

11 files changed

Lines changed: 1930 additions & 199 deletions

File tree

.github/workflows/build-safety.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Build safety
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- dev
8+
- release/**
9+
pull_request:
10+
branches:
11+
- main
12+
- dev
13+
- release/**
14+
15+
jobs:
16+
build-safety:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Install system dependencies
24+
run: |
25+
sudo apt-get update
26+
sudo apt-get install -y \
27+
build-essential \
28+
cmake \
29+
ninja-build \
30+
ccache \
31+
mold \
32+
hyperfine
33+
34+
- name: Configure Vix CLI
35+
run: |
36+
cmake -S . -B build-ci -G Ninja \
37+
-DCMAKE_BUILD_TYPE=Release \
38+
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
39+
40+
- name: Build Vix CLI
41+
run: |
42+
cmake --build build-ci --target vix -- -j"$(nproc)"
43+
44+
- name: Show Vix version
45+
run: |
46+
./build-ci/vix --version || ./build-ci/vix version || true
47+
48+
- name: Run build safety tests
49+
run: |
50+
VIX_BIN="$PWD/build-ci/vix" scripts/test-build-safety.sh
51+
52+
- name: Run build benchmark smoke test
53+
run: |
54+
VIX_BIN="$PWD/build-ci/vix" RUNS=3 WARMUP=1 TARGET=vix scripts/bench-build.sh
55+
56+
- name: Upload benchmark report
57+
uses: actions/upload-artifact@v4
58+
with:
59+
name: vix-build-benchmark
60+
path: .vix/bench/reports/

include/vix/cli/cache/ArtifactCache.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ namespace vix::cli::cache
281281
const std::string &signature,
282282
const std::string &projectFingerprint,
283283
const std::string &buildTarget,
284+
const std::string &preset,
285+
const std::string &buildType,
286+
const std::string &target,
287+
const std::string &compiler,
284288
const std::vector<ProjectInput> &currentInputs);
285289

286290
/**

include/vix/cli/process/Process.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ namespace vix::cli::process
102102
*/
103103
bool verbose = false;
104104

105+
/**
106+
* @brief Explains why Vix rebuilds files or targets.
107+
*/
108+
bool explain = false;
109+
105110
/**
106111
* @brief Optional project directory passed with `--dir`.
107112
*/

scripts/bench-build.sh

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5+
VIX_BIN="${VIX_BIN:-vix}"
6+
TARGET="${TARGET:-vix}"
7+
RUNS="${RUNS:-20}"
8+
WARMUP="${WARMUP:-5}"
9+
10+
BENCH_DIR="${ROOT_DIR}/.vix/bench"
11+
REPORT_DIR="${BENCH_DIR}/reports"
12+
REPORT_FILE="${REPORT_DIR}/build-benchmark.md"
13+
14+
mkdir -p "${REPORT_DIR}"
15+
16+
require_command() {
17+
local cmd="$1"
18+
19+
if ! command -v "$cmd" >/dev/null 2>&1; then
20+
echo "error: required command not found: $cmd" >&2
21+
exit 1
22+
fi
23+
}
24+
25+
count_files() {
26+
local pattern="$1"
27+
28+
find "${ROOT_DIR}" \
29+
-path "${ROOT_DIR}/.git" -prune -o \
30+
-path "${ROOT_DIR}/build*" -prune -o \
31+
-path "${ROOT_DIR}/.vix" -prune -o \
32+
-type f \
33+
\( ${pattern} \) \
34+
-print | wc -l | tr -d ' '
35+
}
36+
37+
detect_cpu() {
38+
if command -v lscpu >/dev/null 2>&1; then
39+
lscpu | awk -F: '/Model name/ { gsub(/^[ \t]+/, "", $2); print $2; exit }'
40+
else
41+
uname -m
42+
fi
43+
}
44+
45+
detect_ram() {
46+
if command -v free >/dev/null 2>&1; then
47+
free -h | awk '/Mem:/ { print $2; exit }'
48+
else
49+
echo "unknown"
50+
fi
51+
}
52+
53+
detect_os() {
54+
if [[ -f /etc/os-release ]]; then
55+
. /etc/os-release
56+
echo "${PRETTY_NAME:-unknown}"
57+
else
58+
uname -a
59+
fi
60+
}
61+
62+
detect_compiler() {
63+
if command -v c++ >/dev/null 2>&1; then
64+
c++ --version | head -n 1
65+
else
66+
echo "unknown"
67+
fi
68+
}
69+
70+
detect_linker() {
71+
if command -v mold >/dev/null 2>&1; then
72+
echo "mold"
73+
return
74+
fi
75+
76+
if command -v ld.lld >/dev/null 2>&1; then
77+
echo "lld"
78+
return
79+
fi
80+
81+
if command -v ld >/dev/null 2>&1; then
82+
ld --version | head -n 1
83+
return
84+
fi
85+
86+
echo "unknown"
87+
}
88+
89+
detect_launcher() {
90+
if command -v sccache >/dev/null 2>&1; then
91+
echo "sccache"
92+
return
93+
fi
94+
95+
if command -v ccache >/dev/null 2>&1; then
96+
echo "ccache"
97+
return
98+
fi
99+
100+
echo "none"
101+
}
102+
103+
detect_vix_version() {
104+
"$VIX_BIN" --version 2>/dev/null || "$VIX_BIN" version 2>/dev/null || echo "unknown"
105+
}
106+
107+
count_compile_tasks() {
108+
local compile_commands="${ROOT_DIR}/build-ninja/compile_commands.json"
109+
110+
if [[ ! -f "$compile_commands" ]]; then
111+
echo "0"
112+
return
113+
fi
114+
115+
python3 - <<PY
116+
import json
117+
from pathlib import Path
118+
119+
path = Path("${compile_commands}")
120+
try:
121+
data = json.loads(path.read_text())
122+
print(len(data) if isinstance(data, list) else 0)
123+
except Exception:
124+
print(0)
125+
PY
126+
}
127+
128+
write_metadata() {
129+
local source_count="$1"
130+
local header_count="$2"
131+
local compile_task_count="$3"
132+
133+
{
134+
echo "# Vix Build Benchmark"
135+
echo
136+
echo "## Environment"
137+
echo
138+
echo "| Field | Value |"
139+
echo "| --- | --- |"
140+
echo "| CPU | $(detect_cpu) |"
141+
echo "| RAM | $(detect_ram) |"
142+
echo "| OS | $(detect_os) |"
143+
echo "| Compiler | $(detect_compiler) |"
144+
echo "| Linker | $(detect_linker) |"
145+
echo "| Launcher | $(detect_launcher) |"
146+
echo "| Vix version | $(detect_vix_version) |"
147+
echo "| Target | ${TARGET} |"
148+
echo "| Runs | ${RUNS} |"
149+
echo "| Warmup | ${WARMUP} |"
150+
echo
151+
echo "## Project"
152+
echo
153+
echo "| Field | Value |"
154+
echo "| --- | --- |"
155+
echo "| Source files | ${source_count} |"
156+
echo "| Header files | ${header_count} |"
157+
echo "| Compile tasks | ${compile_task_count} |"
158+
echo "| Object cache | \$HOME/.vix/cache/objects |"
159+
echo "| Artifact cache | \$HOME/.vix/cache/build |"
160+
echo
161+
echo "## Benchmark"
162+
echo
163+
} > "$REPORT_FILE"
164+
}
165+
166+
run_hyperfine() {
167+
hyperfine \
168+
--warmup "$WARMUP" \
169+
--runs "$RUNS" \
170+
--export-markdown "${REPORT_DIR}/hyperfine.md" \
171+
"${VIX_BIN} build --fast --build-target ${TARGET}" \
172+
"${VIX_BIN} build --build-target ${TARGET}" \
173+
"VIX_GRAPH_EXECUTOR=0 ${VIX_BIN} build --build-target ${TARGET}"
174+
175+
cat "${REPORT_DIR}/hyperfine.md" >> "$REPORT_FILE"
176+
}
177+
178+
run_scenario() {
179+
local name="$1"
180+
shift
181+
182+
echo "## ${name}" >> "$REPORT_FILE"
183+
echo >> "$REPORT_FILE"
184+
185+
{
186+
echo '```txt'
187+
"$@"
188+
echo '```'
189+
} >> "$REPORT_FILE" 2>&1
190+
191+
echo >> "$REPORT_FILE"
192+
}
193+
194+
main() {
195+
require_command "$VIX_BIN"
196+
require_command hyperfine
197+
require_command python3
198+
199+
cd "$ROOT_DIR"
200+
201+
echo "Preparing baseline build..."
202+
"$VIX_BIN" build --build-target "$TARGET" >/dev/null
203+
204+
local source_count
205+
local header_count
206+
local compile_task_count
207+
208+
source_count="$(count_files '-name "*.cpp" -o -name "*.cc" -o -name "*.cxx" -o -name "*.c"')"
209+
header_count="$(count_files '-name "*.hpp" -o -name "*.hh" -o -name "*.hxx" -o -name "*.h" -o -name "*.ipp"')"
210+
compile_task_count="$(count_compile_tasks)"
211+
212+
write_metadata "$source_count" "$header_count" "$compile_task_count"
213+
214+
echo "Running standard benchmark..."
215+
run_hyperfine
216+
217+
echo "Running official scenarios..."
218+
219+
run_scenario "no-op build" \
220+
"$VIX_BIN" build --build-target "$TARGET"
221+
222+
run_scenario "fast path hit" \
223+
"$VIX_BIN" build --fast --build-target "$TARGET"
224+
225+
run_scenario "target build vs all build: target" \
226+
"$VIX_BIN" build --build-target "$TARGET"
227+
228+
run_scenario "target build vs all build: all" \
229+
"$VIX_BIN" build --build-target all
230+
231+
echo "Report written to:"
232+
echo " ${REPORT_FILE}"
233+
}
234+
235+
main "$@"

0 commit comments

Comments
 (0)