Skip to content

Commit a659086

Browse files
committed
Report torch/torchvision versions and binary sizes for every validated build
check_wheel_size only measures linux and linux-aarch64 pip wheels, skips ROCm and libtorch, and exists to enforce a ceiling -- so windows, macos and ROCm builds report no size at all today. Add a per-build report that runs on every OS and never fails the job. It prints two sizes, because they answer different questions: the compressed wheel download size (what users pull from the index, read off pip's output) and the unpacked installed size (measured from the installed package, so it is available on every install path including uv/wheel-variants). Versions come from the installed packages rather than the matrix, so a mismatch between what was requested and what pip resolved is visible. The wheel-size parsing is factored out of check_wheel_size into parse_wheel_size_mb and reused; the ceiling check keeps its current scope and behaviour.
1 parent 4325056 commit a659086

1 file changed

Lines changed: 134 additions & 17 deletions

File tree

.github/scripts/validate_binaries.sh

Lines changed: 134 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,29 @@ cleanup_conda_env() {
247247
fi
248248
}
249249

250+
# Read a wheel's compressed download size, in MB, out of a captured pip log.
251+
#
252+
# $1 = log file, $2 = distribution name as it appears in the wheel filename.
253+
# Prints the size, or nothing when that wheel is absent from the log (already
254+
# satisfied, or installed from a local file). "<dist>-[0-9]" keeps a request for
255+
# "torch" from matching the torchvision-/torchaudio- wheels.
256+
parse_wheel_size_mb() {
257+
local log_file="$1" dist="$2" frag size unit
258+
frag=$(grep -oiE "${dist}-[0-9][^ /]*\.whl \([0-9.]+ ?[kKmMgG]i?B\)" "${log_file}" | tail -1 || true)
259+
if [[ -z ${frag} ]]; then
260+
return 0
261+
fi
262+
size=$(echo "${frag}" | sed -E 's/.*\(([0-9.]+) ?([A-Za-z]+)\)$/\1/')
263+
unit=$(echo "${frag}" | sed -E 's/.*\(([0-9.]+) ?([A-Za-z]+)\)$/\2/')
264+
case ${unit} in
265+
B) awk "BEGIN{printf \"%.1f\", ${size}/1024/1024}" ;;
266+
kB|KB|kiB|KiB) awk "BEGIN{printf \"%.1f\", ${size}/1024}" ;;
267+
MB|MiB) awk "BEGIN{printf \"%.1f\", ${size}}" ;;
268+
GB|GiB) awk "BEGIN{printf \"%.1f\", ${size}*1024}" ;;
269+
*) echo "::warning::wheel-size: unrecognized size unit '${unit}' for ${dist}" >&2 ;;
270+
esac
271+
}
272+
250273
# Fail the build if the installed torch wheel exceeds a hard size ceiling.
251274
#
252275
# Scope: Linux x86_64 + aarch64 wheels only, excluding ROCm (whose wheels are
@@ -269,27 +292,13 @@ check_wheel_size() {
269292
return 0
270293
fi
271294

272-
# Pull the torch wheel's size off pip's Downloading/Using-cached line, e.g.
273-
# Downloading torch-2.10.0.dev...-linux_x86_64.whl (812.4 MB)
274-
# torch-[0-9] isolates the torch wheel from torchvision-/torchaudio-.
275-
local frag
276-
frag=$(grep -oiE "torch-[0-9][^ /]*\.whl \([0-9.]+ ?[kKmMgG]i?B\)" "${log_file}" | tail -1 || true)
277-
if [[ -z ${frag} ]]; then
295+
local size_mb
296+
size_mb=$(parse_wheel_size_mb "${log_file}" torch)
297+
if [[ -z ${size_mb} ]]; then
278298
echo "::warning::wheel-size check: could not find the torch wheel size in the pip output; skipping"
279299
return 0
280300
fi
281301

282-
local size unit size_mb
283-
size=$(echo "${frag}" | sed -E 's/.*\(([0-9.]+) ?([A-Za-z]+)\)$/\1/')
284-
unit=$(echo "${frag}" | sed -E 's/.*\(([0-9.]+) ?([A-Za-z]+)\)$/\2/')
285-
case ${unit} in
286-
B) size_mb=$(awk "BEGIN{printf \"%.1f\", ${size}/1024/1024}") ;;
287-
kB|KB|kiB|KiB) size_mb=$(awk "BEGIN{printf \"%.1f\", ${size}/1024}") ;;
288-
MB|MiB) size_mb=$(awk "BEGIN{printf \"%.1f\", ${size}}") ;;
289-
GB|GiB) size_mb=$(awk "BEGIN{printf \"%.1f\", ${size}*1024}") ;;
290-
*) echo "::warning::wheel-size check: unrecognized size unit '${unit}'; skipping"; return 0 ;;
291-
esac
292-
293302
# Always surface the measured size (as an annotation) whether or not the
294303
# check passes, so it is visible on the run summary of a successful job too.
295304
echo "::notice::torch wheel size: ${size_mb} MB (arch=${MATRIX_GPU_ARCH_TYPE:-cpu} os=${TARGET_OS} py=${MATRIX_PYTHON_VERSION:-?}); ceiling ${threshold_mb} MB"
@@ -299,6 +308,107 @@ check_wheel_size() {
299308
fi
300309
}
301310

311+
# Report what this build actually installed, and how big it is.
312+
#
313+
# Complements check_wheel_size, which only measures linux/linux-aarch64 pip
314+
# wheels and exists to enforce a ceiling: this runs for every build on every OS
315+
# and never fails, so windows/macos/ROCm sizes are visible too.
316+
#
317+
# Two sizes are reported because they answer different questions:
318+
# wheel -- compressed download size, what users pull from the index.
319+
# Only available when pip printed it (absent on the uv/variants
320+
# path and when the wheel was already satisfied).
321+
# installed -- unpacked bytes on disk, measured from the installed package,
322+
# so it is available on every install path.
323+
#
324+
# Runs while the env is still active: cleanup_conda_env removes it on non-linux.
325+
# Values are read from the installed packages rather than from the matrix, so a
326+
# mismatch between what was requested and what pip resolved shows up here.
327+
write_build_report() {
328+
local torch_wheel_mb="${1:-}" vision_wheel_mb="${2:-}"
329+
local report
330+
331+
# cd out of the repo: this runs from the pytorch/pytorch checkout, where
332+
# `import torch` would pick up the source tree instead of the install.
333+
report=$(cd "${TMPDIR:-/tmp}" 2>/dev/null || cd "${HOME}"; "${PYTHON_RUN}" - \
334+
"${TARGET_OS}" "${MATRIX_PYTHON_VERSION:-?}" "${MATRIX_GPU_ARCH_TYPE:-cpu}" \
335+
"${MATRIX_GPU_ARCH_VERSION:-}" "${torch_wheel_mb}" "${vision_wheel_mb}" <<'PY'
336+
import os
337+
import sys
338+
339+
target_os, py, arch_type, arch_ver, torch_wheel, vision_wheel = sys.argv[1:7]
340+
341+
342+
def installed_mb(mod):
343+
root = os.path.dirname(mod.__file__)
344+
total = 0
345+
for dirpath, _, names in os.walk(root):
346+
for n in names:
347+
try:
348+
total += os.path.getsize(os.path.join(dirpath, n))
349+
except OSError:
350+
pass
351+
return "%.1f MB" % (total / 1024 / 1024)
352+
353+
354+
def mb(value):
355+
return "%s MB" % value if value else "-"
356+
357+
358+
rows = [("build", "%s / py%s / %s%s" % (target_os, py, arch_type,
359+
" " + arch_ver if arch_ver else ""))]
360+
361+
try:
362+
import torch
363+
rows.append(("torch", torch.__version__))
364+
rows.append(("torch wheel", mb(torch_wheel)))
365+
rows.append(("torch installed", installed_mb(torch)))
366+
rows.append(("CUDA", torch.version.cuda or "-"))
367+
try:
368+
v = torch.backends.cudnn.version()
369+
rows.append(("cuDNN", "%d.%d.%d" % (v // 10000, v % 10000 // 100, v % 100)
370+
if v else "-"))
371+
except Exception:
372+
rows.append(("cuDNN", "-"))
373+
try:
374+
rows.append(("NCCL", ".".join(str(p) for p in torch.cuda.nccl.version())))
375+
except Exception:
376+
rows.append(("NCCL", "-"))
377+
except Exception as e: # never fail the build over a report
378+
rows.append(("torch", "import failed: %s" % e))
379+
380+
try:
381+
import torchvision
382+
rows.append(("torchvision", torchvision.__version__))
383+
rows.append(("torchvision wheel", mb(vision_wheel)))
384+
rows.append(("torchvision installed", installed_mb(torchvision)))
385+
except Exception:
386+
rows.append(("torchvision", "-"))
387+
388+
print("| field | value |")
389+
print("| --- | --- |")
390+
for k, v in rows:
391+
print("| %s | %s |" % (k, v))
392+
PY
393+
) || report="| field | value |
394+
| --- | --- |
395+
| report | failed to collect |"
396+
397+
echo "--- Build report"
398+
echo "${report}"
399+
400+
# The job summary file is not reachable from inside the validation
401+
# container, so only append when the runner actually exposes a writable one.
402+
# stderr is redirected before the append so a non-writable path fails quietly
403+
if [[ -n ${GITHUB_STEP_SUMMARY:-} ]] && : 2>/dev/null >>"${GITHUB_STEP_SUMMARY}"; then
404+
{
405+
echo "### ${MATRIX_PACKAGE_TYPE:-wheel}: ${TARGET_OS} / py${MATRIX_PYTHON_VERSION:-?} / ${MATRIX_GPU_ARCH_TYPE:-cpu} ${MATRIX_GPU_ARCH_VERSION:-}"
406+
echo "${report}"
407+
echo
408+
} >> "${GITHUB_STEP_SUMMARY}"
409+
fi
410+
}
411+
302412
#######################################
303413
# Main Script
304414
#######################################
@@ -393,6 +503,8 @@ if [[ ${MATRIX_PACKAGE_TYPE} == 'wheel' ]]; then
393503
fi
394504

395505
# Install packages
506+
TORCH_WHEEL_MB=""
507+
TORCHVISION_WHEEL_MB=""
396508
if [[ ${USE_WHEEL_VARIANTS:-} == 'true' ]]; then
397509
install_wheel_variants
398510
else
@@ -404,6 +516,8 @@ else
404516
WHEEL_INSTALL_LOG="$(mktemp)"
405517
eval "${INSTALLATION}" 2>&1 | tee "${WHEEL_INSTALL_LOG}"
406518
check_wheel_size "${WHEEL_INSTALL_LOG}"
519+
TORCH_WHEEL_MB="$(parse_wheel_size_mb "${WHEEL_INSTALL_LOG}" torch)"
520+
TORCHVISION_WHEEL_MB="$(parse_wheel_size_mb "${WHEEL_INSTALL_LOG}" torchvision)"
407521
rm -f "${WHEEL_INSTALL_LOG}"
408522
fi
409523

@@ -413,6 +527,9 @@ install_numpy_1x
413527
# Run tests
414528
run_smoke_tests "${TEST_SUFFIX}"
415529

530+
# Report versions and sizes for this build
531+
write_build_report "${TORCH_WHEEL_MB}" "${TORCHVISION_WHEEL_MB}"
532+
416533
# Restore PATH for macos-arm64
417534
if [[ ${TARGET_OS} == 'macos-arm64' ]]; then
418535
export PATH=${OLD_PATH}

0 commit comments

Comments
 (0)