@@ -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
393503fi
394504
395505# Install packages
506+ TORCH_WHEEL_MB=" "
507+ TORCHVISION_WHEEL_MB=" "
396508if [[ ${USE_WHEEL_VARIANTS:- } == ' true' ]]; then
397509 install_wheel_variants
398510else
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} "
408522fi
409523
@@ -413,6 +527,9 @@ install_numpy_1x
413527# Run tests
414528run_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
417534if [[ ${TARGET_OS} == ' macos-arm64' ]]; then
418535 export PATH=${OLD_PATH}
0 commit comments