Skip to content

Commit b7d547b

Browse files
committed
measure: readings for the design of #734 (vcpkg toolset selection, CRT linkage, deploy edges)
A temporary measurement branch. The workflow reads vcpkg's behaviour on a Visual Studio machine and with Visual Studio masked, the C++ runtime contract against vcpkg's CRT linkage with mcpp 2026.9.28.2 and plugins 0.16.0, and the time of 1270 deploy edges. It is not intended to be merged.
1 parent dbf7194 commit b7d547b

1 file changed

Lines changed: 305 additions & 0 deletions

File tree

‎.github/workflows/measure-734.yml‎

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
name: measure 734
2+
3+
# Readings for the design of #734 (.agents/docs/2026-09-28-build-cost-foreign-
4+
# toolsets-and-library-surface-design.md). Every leg prints `READING <id>: ...`
5+
# lines and never fails the job on the value it reads; a job fails only when the
6+
# harness itself cannot run.
7+
#
8+
# M1 vcpkg on a Visual Studio machine: does selecting the instance through the
9+
# environment (VCPKG_VISUAL_STUDIO_PATH) keep the ABI hash of a port?
10+
# M2 vcpkg on a Visual Studio machine: a chain-loaded triplet (toolset
11+
# "external") against an MSBuild port (libusb), a CMake port (zlib) as the
12+
# control of the chain-loaded setup, and the hybrid with vcvars loaded.
13+
# M3 vcpkg with Visual Studio masked and the managed msvc@14.44.35207 named by a
14+
# chain-loaded triplet: zlib (CMake) and icu (make under msys).
15+
# P3 the same toolset copied to another path: is the port restored from the
16+
# binary cache (same ABI hash)?
17+
# E2b mcpp 2026.9.28.2 + mcpp:plugins 0.16.0 + fmt: cxx_runtime x triplet.
18+
# E4 the time of 1270 deploy edges on a first build.
19+
20+
on:
21+
push:
22+
branches: [ 'measure/734-readings' ]
23+
workflow_dispatch:
24+
25+
env:
26+
XLINGS_NON_INTERACTIVE: '1'
27+
BASELINE: ee6a47dac031930715bea2e6dfb9ad60caaa5d83
28+
29+
jobs:
30+
vcpkg-vs:
31+
name: M1 M2 (Visual Studio)
32+
runs-on: windows-2025
33+
timeout-minutes: 90
34+
defaults: { run: { shell: bash } }
35+
steps:
36+
- name: Locate Visual Studio and load its developer environment
37+
shell: pwsh
38+
run: |
39+
$vsp = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
40+
Write-Host "VS: $vsp"
41+
$bat = Join-Path $vsp "VC\Auxiliary\Build\vcvars64.bat"
42+
$lines = cmd /d /s /c "`"$bat`" >nul && set"
43+
foreach ($l in $lines) {
44+
$k, $v = $l -split '=', 2
45+
if ($k -in 'INCLUDE', 'LIB', 'LIBPATH', 'Path') { Set-Item "env:$k" $v }
46+
}
47+
$out = @(
48+
"VSP=$vsp",
49+
"INCLUDE=$env:INCLUDE", "LIB=$env:LIB", "LIBPATH=$env:LIBPATH",
50+
"MEASURE_CL=$((Get-Command cl.exe).Source)",
51+
"MEASURE_RC=$((Get-Command rc.exe).Source)",
52+
"MEASURE_MT=$((Get-Command mt.exe).Source)",
53+
"MEASURE_VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT"
54+
)
55+
$out | ForEach-Object { Write-Host $_ }
56+
$out | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
57+
58+
- name: Locate vcpkg
59+
run: |
60+
V="$(cygpath -u "$VCPKG_INSTALLATION_ROOT")/vcpkg.exe"
61+
test -x "$V" || { echo "::error::no vcpkg at $VCPKG_INSTALLATION_ROOT"; exit 1; }
62+
"$V" version | head -1
63+
echo "V=$V" >> "$GITHUB_ENV"
64+
mkdir -p "$RUNNER_TEMP/bincache"
65+
echo "VCPKG_BINARY_SOURCES=clear;files,$(cygpath -w "$RUNNER_TEMP/bincache"),readwrite" >> "$GITHUB_ENV"
66+
67+
- name: Write the manifests and the chain-loaded triplets
68+
run: |
69+
set -e
70+
T="$RUNNER_TEMP/triplets"; mkdir -p "$T"
71+
base="set(VCPKG_TARGET_ARCHITECTURE x64)
72+
set(VCPKG_CRT_LINKAGE dynamic)
73+
set(VCPKG_LIBRARY_LINKAGE dynamic)"
74+
chain='set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/chain.cmake")
75+
set(VCPKG_ENV_PASSTHROUGH_UNTRACKED INCLUDE LIB LIBPATH MEASURE_CL MEASURE_RC MEASURE_MT MEASURE_VCPKG_ROOT)'
76+
printf '%s\n%s\n' "$base" "$chain" | sed 's/^ *//' > "$T/x64-windows-chain.cmake"
77+
printf '%s\n%s\nset(VCPKG_LOAD_VCVARS_ENV ON)\n' "$base" "$chain" | sed 's/^ *//' > "$T/x64-windows-chainvc.cmake"
78+
cat > "$T/chain.cmake" <<'EOF'
79+
set(CMAKE_C_COMPILER "$ENV{MEASURE_CL}")
80+
set(CMAKE_CXX_COMPILER "$ENV{MEASURE_CL}")
81+
set(CMAKE_RC_COMPILER "$ENV{MEASURE_RC}")
82+
set(CMAKE_MT "$ENV{MEASURE_MT}")
83+
include("$ENV{MEASURE_VCPKG_ROOT}/scripts/toolchains/windows.cmake")
84+
EOF
85+
sed -i 's/^ *//' "$T/chain.cmake"
86+
cat "$T"/*.cmake
87+
for p in zlib libusb; do
88+
for leg in a b; do
89+
d="$RUNNER_TEMP/m-$p-$leg"; mkdir -p "$d"
90+
printf '{ "name": "m%s", "version": "0.1.0", "dependencies": ["%s"] }\n' "$leg" "$p" > "$d/vcpkg.json"
91+
done
92+
done
93+
94+
- name: M1 the instance named through the environment
95+
continue-on-error: true
96+
run: |
97+
set +e +o pipefail
98+
abi() { cat "$1"/vcpkg_installed/x64-windows/share/zlib/vcpkg_abi_info.txt 2>/dev/null | sha256sum | cut -c1-16; }
99+
( cd "$RUNNER_TEMP/m-zlib-a" && "$V" install --triplet x64-windows ) > m1a.log 2>&1; echo "READING M1a: default instance, exit $?"
100+
( cd "$RUNNER_TEMP/m-zlib-b" && VCPKG_VISUAL_STUDIO_PATH="$VSP" "$V" install --triplet x64-windows ) > m1b.log 2>&1; echo "READING M1b: VCPKG_VISUAL_STUDIO_PATH, exit $?"
101+
echo "READING M1: abi_info a=$(abi "$RUNNER_TEMP/m-zlib-a") b=$(abi "$RUNNER_TEMP/m-zlib-b")"
102+
echo "READING M1: leg b $(grep -iE 'Restored [0-9]+ package|Building zlib' m1b.log | head -2 | tr '\n' ' ')"
103+
ls -R "$RUNNER_TEMP/bincache" | grep -i '\.zip' | head
104+
105+
- name: M2 chain-loaded triplets against CMake and MSBuild ports
106+
continue-on-error: true
107+
run: |
108+
set +e +o pipefail
109+
T=$(cygpath -w "$RUNNER_TEMP/triplets")
110+
run() { # $1 port, $2 triplet, $3 label
111+
d="$RUNNER_TEMP/m2-$1-$2"; rm -rf "$d"; mkdir -p "$d"
112+
cp "$RUNNER_TEMP/m-$1-a/vcpkg.json" "$d/"
113+
( cd "$d" && "$V" install --triplet "$2" --overlay-triplets="$T" ) > "m2-$1-$2.log" 2>&1
114+
rc=$?
115+
echo "READING M2 $3: $1 under $2 exit $rc"
116+
[ $rc = 0 ] || { grep -iE 'error|PlatformToolset|external' "m2-$1-$2.log" | head -8; tail -5 "m2-$1-$2.log"; }
117+
}
118+
run libusb x64-windows "control"
119+
run zlib x64-windows-chain "chain-loaded, CMake port"
120+
run libusb x64-windows-chain "chain-loaded, MSBuild port"
121+
run libusb x64-windows-chainvc "chain-loaded with vcvars, MSBuild port"
122+
run zlib x64-windows-chainvc "chain-loaded with vcvars, CMake port"
123+
124+
- uses: actions/upload-artifact@v4
125+
if: always()
126+
with: { name: m1-m2-logs, path: '*.log' }
127+
128+
vcpkg-managed:
129+
name: M3 P3 (Visual Studio masked, managed msvc)
130+
runs-on: windows-2025
131+
timeout-minutes: 150
132+
defaults: { run: { shell: bash } }
133+
steps:
134+
- name: Mask Visual Studio
135+
shell: pwsh
136+
run: |
137+
$ErrorActionPreference = 'Continue'
138+
$vswhere = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
139+
if (Test-Path $vswhere) { Rename-Item $vswhere "vswhere.exe.masked" }
140+
Resolve-Path "C:\Program Files*\Microsoft Visual Studio\*\*\VC" -ErrorAction SilentlyContinue | ForEach-Object {
141+
try { Rename-Item -LiteralPath $_.Path -NewName "VC.masked" -ErrorAction Stop }
142+
catch { Write-Host " rename failed: $($_.Exception.Message)" }
143+
}
144+
foreach ($v in @('VSINSTALLDIR','VCINSTALLDIR','VCToolsInstallDir','VS170COMNTOOLS','VS160COMNTOOLS','VS150COMNTOOLS')) {
145+
"$v=" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
146+
}
147+
$left = Get-ChildItem "C:\Program Files*\Microsoft Visual Studio\*\*\VC\Tools\MSVC" -Directory -ErrorAction SilentlyContinue
148+
if ($left) { Write-Host "FAIL: VC tools still present after masking"; exit 1 }
149+
150+
- name: Install xlings
151+
shell: pwsh
152+
run: |
153+
irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
154+
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
155+
"$env:USERPROFILE\.xlings\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
156+
157+
- name: Install msvc@14.44.35207 and derive its environment
158+
run: |
159+
set -e
160+
( cd "$RUNNER_TEMP" && xlings install msvc@14.44.35207 -y ) > msvc-install.log 2>&1 || { tail -30 msvc-install.log; exit 1; }
161+
X="$(cygpath -u "$USERPROFILE")/.xlings/data/xpkgs"
162+
CL=$(find "$X"/xim-x-msvc -path '*Hostx64/x64/cl.exe' | head -1)
163+
test -n "$CL" || { echo "::error::no cl.exe under $X/xim-x-msvc"; exit 1; }
164+
TOOLS=${CL%/bin/Hostx64/x64/cl.exe}
165+
WH=$(find "$X"/xim-x-windows-sdk -name windows.h -path '*/um/*' | head -1)
166+
INCV=$(dirname "$(dirname "$WH")"); VER=$(basename "$INCV"); SDK=$(dirname "$(dirname "$INCV")")
167+
RC=$(find "$SDK" -path "*$VER*x64/rc.exe" | head -1); MT=$(find "$SDK" -path "*$VER*x64/mt.exe" | head -1)
168+
echo "tools=$TOOLS sdk=$SDK ver=$VER rc=$RC mt=$MT"
169+
w() { cygpath -w "$1"; }
170+
echo "TOOLS=$TOOLS" >> "$GITHUB_ENV"; echo "SDK=$SDK" >> "$GITHUB_ENV"; echo "SDKVER=$VER" >> "$GITHUB_ENV"
171+
echo "MEASURE_RC=$(w "$RC")" >> "$GITHUB_ENV"; echo "MEASURE_MT=$(w "$MT")" >> "$GITHUB_ENV"
172+
echo "MEASURE_VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
173+
mkdir -p "$RUNNER_TEMP/bincache"
174+
echo "VCPKG_BINARY_SOURCES=clear;files,$(cygpath -w "$RUNNER_TEMP/bincache"),readwrite" >> "$GITHUB_ENV"
175+
echo "V=$(cygpath -u "$VCPKG_INSTALLATION_ROOT")/vcpkg.exe" >> "$GITHUB_ENV"
176+
177+
- name: M3 and P3 chain-loaded managed toolset
178+
continue-on-error: true
179+
run: |
180+
set +e +o pipefail
181+
T="$RUNNER_TEMP/triplets"; mkdir -p "$T"
182+
printf '%s\n' 'set(VCPKG_TARGET_ARCHITECTURE x64)' 'set(VCPKG_CRT_LINKAGE dynamic)' 'set(VCPKG_LIBRARY_LINKAGE dynamic)' \
183+
'set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/chain.cmake")' \
184+
'set(VCPKG_ENV_PASSTHROUGH_UNTRACKED INCLUDE LIB LIBPATH MEASURE_CL MEASURE_RC MEASURE_MT MEASURE_VCPKG_ROOT)' \
185+
> "$T/x64-windows-chain.cmake"
186+
printf '%s\n' 'set(CMAKE_C_COMPILER "$ENV{MEASURE_CL}")' 'set(CMAKE_CXX_COMPILER "$ENV{MEASURE_CL}")' \
187+
'set(CMAKE_RC_COMPILER "$ENV{MEASURE_RC}")' 'set(CMAKE_MT "$ENV{MEASURE_MT}")' \
188+
'include("$ENV{MEASURE_VCPKG_ROOT}/scripts/toolchains/windows.cmake")' > "$T/chain.cmake"
189+
setenv() { # $1 = the toolset directory
190+
w() { cygpath -w "$1"; }
191+
export MEASURE_CL="$(w "$1/bin/Hostx64/x64/cl.exe")"
192+
I="$SDK/Include/$SDKVER"; L="$SDK/Lib/$SDKVER"
193+
export INCLUDE="$(w "$1/include");$(w "$I/ucrt");$(w "$I/um");$(w "$I/shared");$(w "$I/winrt");$(w "$I/cppwinrt")"
194+
export LIB="$(w "$1/lib/x64");$(w "$L/ucrt/x64");$(w "$L/um/x64")"
195+
export LIBPATH="$(w "$1/lib/x64")"
196+
}
197+
run() { # $1 port, $2 label, $3 dir suffix
198+
d="$RUNNER_TEMP/m3-$1-$3"; rm -rf "$d"; mkdir -p "$d"
199+
printf '{ "name": "m", "version": "0.1.0", "dependencies": ["%s"] }\n' "$1" > "$d/vcpkg.json"
200+
( cd "$d" && "$V" install --triplet x64-windows-chain --overlay-triplets="$(cygpath -w "$T")" ) > "m3-$1-$3.log" 2>&1
201+
rc=$?
202+
echo "READING $2: $1 exit $rc; $(grep -iE 'Restored [0-9]+ package' "m3-$1-$3.log" | head -1)"
203+
[ $rc = 0 ] || { grep -iE 'error' "m3-$1-$3.log" | head -8; tail -5 "m3-$1-$3.log"; }
204+
}
205+
setenv "$TOOLS"
206+
run zlib "M3 managed, CMake port" a
207+
run icu "M3 managed, make port" a
208+
# P3: the same toolset at another path; a restore means the same ABI hash.
209+
cp -r "$TOOLS" "$RUNNER_TEMP/tc2"
210+
setenv "$RUNNER_TEMP/tc2"
211+
run zlib "P3 same toolset, other path" b
212+
ls -R "$RUNNER_TEMP/bincache" | grep -ic '\.zip' | sed 's/^/READING P3: archives in the cache: /'
213+
214+
- uses: actions/upload-artifact@v4
215+
if: always()
216+
with: { name: m3-p3-logs, path: '*.log' }
217+
218+
mcpp-legs:
219+
name: E2b E4 (mcpp 2026.9.28.2)
220+
runs-on: windows-2025
221+
timeout-minutes: 120
222+
defaults: { run: { shell: bash } }
223+
steps:
224+
- name: Install xlings
225+
shell: pwsh
226+
run: |
227+
irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
228+
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
229+
"$env:USERPROFILE\.xlings\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
230+
231+
- name: Install mcpp 2026.9.28.2
232+
run: |
233+
set -e
234+
( cd "$RUNNER_TEMP" && xlings install mcpp@2026.9.28.2 -y ) > mcpp-install.log 2>&1 || { tail -30 mcpp-install.log; exit 1; }
235+
M="$(cygpath -u "$USERPROFILE")/.xlings/data/xpkgs/xim-x-mcpp/2026.9.28.2/bin/mcpp.exe"
236+
"$M" --version
237+
"$M" self config --mirror GLOBAL
238+
echo "M=$M" >> "$GITHUB_ENV"
239+
240+
- name: E2b the C++ runtime contract against vcpkg's CRT linkage
241+
continue-on-error: true
242+
run: |
243+
set +e +o pipefail
244+
for crt in toolchain-coupled self-contained; do
245+
for trip in x64-windows x64-windows-static-md; do
246+
d="$RUNNER_TEMP/e2b-$crt-$trip"; mkdir -p "$d/src"
247+
printf '[package]\nname = "crtprobe"\nversion = "0.1.0"\nstandard = "c++23"\n\n[toolchain]\nwindows = "llvm@22.1.8"\n\n[build]\ncxx_runtime = "%s"\n\n[build-dependencies]\nmcpp.plugins = { version = "0.16.0", features = ["deps-vcpkg"], host-module = true }\n' "$crt" > "$d/mcpp.toml"
248+
printf '{ "name": "crtprobe", "version": "0.1.0", "dependencies": ["fmt"], "builtin-baseline": "%s" }\n' "$BASELINE" > "$d/vcpkg.json"
249+
cat > "$d/build.mcpp" <<EOF
250+
import std;
251+
import mcpp;
252+
import mcpp.deps.vcpkg;
253+
int main() {
254+
mcpp::deps::vcpkg::options o;
255+
o.triplet = "$trip";
256+
o.libraries = {"fmt"};
257+
return mcpp::deps::vcpkg::use(o) ? 0 : 1;
258+
}
259+
EOF
260+
sed -i 's/^ //' "$d/build.mcpp"
261+
printf '#include <fmt/format.h>\n#include <string>\nint main() { std::string s = fmt::format("{}-{}", 4, 2); return s == "4-2" ? 0 : 3; }\n' > "$d/src/main.cpp"
262+
( cd "$d" && "$M" build ) > "e2b-$crt-$trip.log" 2>&1; b=$?
263+
r=skip
264+
if [ $b = 0 ]; then ( cd "$d" && "$M" run ) >> "e2b-$crt-$trip.log" 2>&1; r=$?; fi
265+
echo "READING E2b: cxx_runtime=$crt triplet=$trip build exit $b, run exit $r"
266+
grep -iE 'LNK2038|mismatch|FAILIFMISMATCH|RuntimeLibrary|error' "e2b-$crt-$trip.log" | head -6
267+
done
268+
done
269+
270+
- name: E4 the time of deploy edges on a first build
271+
continue-on-error: true
272+
run: |
273+
set +e +o pipefail
274+
for n in 0 1270; do
275+
d="$RUNNER_TEMP/e4-$n"; mkdir -p "$d/src" "$d/data"
276+
for i in $(seq 1 $n); do echo "$i" > "$d/data/f$i.txt"; done
277+
printf '[package]\nname = "e4"\nversion = "0.1.0"\nstandard = "c++23"\n' > "$d/mcpp.toml"
278+
printf 'int main() { return 0; }\n' > "$d/src/main.cpp"
279+
cat > "$d/build.mcpp" <<EOF
280+
import std;
281+
import mcpp;
282+
int main() {
283+
for (int i = 1; i <= $n; ++i) {
284+
const std::string f = "data/f" + std::to_string(i) + ".txt";
285+
mcpp::deploy(f.c_str(), "data");
286+
}
287+
return 0;
288+
}
289+
EOF
290+
sed -i 's/^ //' "$d/build.mcpp"
291+
for run in 1 2; do
292+
rm -rf "$d/target"
293+
s=$(date +%s.%N); ( cd "$d" && "$M" build ) > "e4-$n-$run.log" 2>&1; rc=$?; e=$(date +%s.%N)
294+
log=$(find "$d/target" -name .ninja_log | head -1)
295+
stats=$(awk -F'\t' 'NR>1 && $4 ~ /data[\\\/]f[0-9]+\.txt$/ {n++; s+=$2-$1; if(min==""||$1<min)min=$1; if($2>max)max=$2} END {printf "edges=%d sum=%.1fs span=%.1fs", n, s/1000, (max-min)/1000}' "$log" 2>/dev/null)
296+
echo "READING E4: n=$n run=$run exit $rc wall=$(awk "BEGIN { printf \"%.1f\", $e - $s }")s $stats"
297+
done
298+
done
299+
d="$RUNNER_TEMP/e4-1270"; rm -rf "$RUNNER_TEMP/e4-copy"
300+
s=$(date +%s.%N); cp -r "$d/data" "$RUNNER_TEMP/e4-copy"; e=$(date +%s.%N)
301+
echo "READING E4: one process copying the same 1270 files: $(awk "BEGIN { printf \"%.1f\", $e - $s }")s"
302+
303+
- uses: actions/upload-artifact@v4
304+
if: always()
305+
with: { name: e2b-e4-logs, path: '*.log' }

0 commit comments

Comments
 (0)