Skip to content

Commit aa4832f

Browse files
Merge branch 'main' into support-spark2.5-ci
2 parents 9f2af5f + 852b1ff commit aa4832f

123 files changed

Lines changed: 5645 additions & 490 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2bb2a9c522e7f944bf98c02c9b85fd959fa0bf0b
1+
e91899ca45f99811049ac7d539820f92a9acddde
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# Installs the NVIDIA display driver on a Windows GPU runner. The runner images carry the
8+
# GPU but no driver, so without this nvcuda.dll is missing and every CUDA call fails with
9+
# cudaErrorInsufficientDriver. The same driver, from the same place, that PyTorch's Windows
10+
# CUDA smoke tests install first (.ci/pytorch/windows/internal/driver_update.bat in
11+
# pytorch/pytorch), so both projects test against one driver.
12+
$ErrorActionPreference = "Stop"
13+
$version = "580.88"
14+
$installer = Join-Path $env:RUNNER_TEMP "$version-data-center-tesla-desktop-win10-win11-64bit-dch-international.exe"
15+
$url = "https://ossci-windows.s3.amazonaws.com/$(Split-Path $installer -Leaf)"
16+
17+
$nvcuda = Join-Path $env:SystemRoot "System32\nvcuda.dll"
18+
if (Test-Path $nvcuda) {
19+
Write-Host "NVIDIA driver already present: $((Get-Item $nvcuda).VersionInfo.FileVersion)"
20+
exit 0
21+
}
22+
curl.exe --retry 3 -fsSL $url --output $installer
23+
if ($LASTEXITCODE -ne 0) { throw "downloading the NVIDIA driver from $url failed" }
24+
$process = Start-Process -FilePath $installer -ArgumentList "-s", "-noreboot" -Wait -PassThru
25+
Remove-Item $installer -ErrorAction SilentlyContinue
26+
if ($process.ExitCode -ne 0) { throw "the NVIDIA driver installer exited with $($process.ExitCode)" }
27+
if (-not (Test-Path $nvcuda)) { throw "the NVIDIA driver installed but $nvcuda is missing" }
28+
Write-Host "NVIDIA driver $version installed: $((Get-Item $nvcuda).VersionInfo.FileVersion)"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# Builds and runs the CUDA backend's runtime C++ tests on a Windows GPU runner, the
8+
# counterpart of the unittest-cuda-runtime job in cuda.yml. The Windows runners carry
9+
# data-center GPUs in TCC mode, which have no memory pools, so this is also what covers the
10+
# allocator's synchronous fallback; the Linux job covers the pool path.
11+
$ErrorActionPreference = "Stop"
12+
13+
# Windows PowerShell 5.1 does not stop on a failing native command.
14+
function Invoke-Native {
15+
param([Parameter(Mandatory = $true)][scriptblock]$Command)
16+
& $Command
17+
if ($LASTEXITCODE -ne 0) {
18+
throw "exit code ${LASTEXITCODE}: $Command"
19+
}
20+
}
21+
22+
& "$PSScriptRoot\install_nvidia_driver_windows.ps1"
23+
24+
$cudaNvcc = Join-Path $env:CUDA_HOME "bin\nvcc.exe"
25+
if (-not (Test-Path $cudaNvcc)) { throw "CUDA compiler not found at '$cudaNvcc'" }
26+
$env:CUDACXX = $cudaNvcc
27+
$env:PATH = "$env:CUDA_HOME\bin\x64;$env:CUDA_HOME\bin;$env:PATH"
28+
# The runner's GPU has no memory pools, which is what makes this job cover the
29+
# allocator's fallback; fail rather than skip those tests if it ever has them.
30+
$env:EXECUTORCH_CUDA_TEST_REQUIRE_NO_MEMORY_POOLS = "1"
31+
32+
$tests = @(
33+
"test_cuda_allocator",
34+
"test_cuda_mutable_state",
35+
"test_cuda_weight_cache",
36+
"test_cuda_sort_rand",
37+
"test_cuda_guard",
38+
"test_cuda_stream_guard"
39+
)
40+
$numCores = [Math]::Max([Environment]::ProcessorCount - 1, 1)
41+
Invoke-Native {
42+
cmake --preset llm-release-cuda -DEXECUTORCH_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=20 `
43+
-T "cuda=$env:CUDA_HOME" "-DCMAKE_CUDA_COMPILER=$cudaNvcc" "-DCUDAToolkit_ROOT=$env:CUDA_HOME"
44+
}
45+
Invoke-Native { cmake --build cmake-out --config Release -j $numCores --target $tests }
46+
foreach ($test in $tests) {
47+
Invoke-Native { ctest --test-dir cmake-out -C Release -R "^$test`$" --output-on-failure -V }
48+
}

‎.ci/scripts/test_ios_ci.sh‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,17 @@ xcodebuild test \
108108
# NB: https://docs.aws.amazon.com/devicefarm/latest/developerguide/test-types-ios-xctest-ui.html
109109
say "Package The Test Suite"
110110

111+
DERIVED_DATA_PATH="$(pwd)/cmake-out/ios-demo-derived-data"
112+
BUILD_DIR="${DERIVED_DATA_PATH}/Build/Products"
113+
MODE="Debug"
114+
PLATFORM="iphoneos"
115+
111116
xcodebuild build-for-testing \
112117
-project "$APP_PATH.xcodeproj" \
113118
-scheme MobileNetClassifierTest \
114-
-destination platform="iOS" \
119+
-configuration "${MODE}" \
120+
-derivedDataPath "${DERIVED_DATA_PATH}" \
121+
-destination "generic/platform=iOS" \
115122
-allowProvisioningUpdates \
116123
DEVELOPMENT_TEAM=78E7V7QP35 \
117124
CODE_SIGN_STYLE=Manual \
@@ -120,12 +127,7 @@ xcodebuild build-for-testing \
120127
CODE_SIGNING_REQUIRED=No \
121128
CODE_SIGNING_ALLOWED=No
122129

123-
# The hack to figure out where the xctest package locates
124-
BUILD_DIR=$(xcodebuild -showBuildSettings -project "$APP_PATH.xcodeproj" -json | jq -r ".[0].buildSettings.BUILD_DIR")
125-
126130
# Prepare the demo app
127-
MODE="Debug"
128-
PLATFORM="iphoneos"
129131
pushd "${BUILD_DIR}/${MODE}-${PLATFORM}"
130132

131133
rm -rf Payload && mkdir Payload

‎.ci/scripts/test_llama.sh‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,7 @@ RESULT=$(cat result.txt)
276276
EXPECTED_PREFIX="Once upon a time,"
277277
# Expected result - may take too long to generate:
278278
# "Once upon a time, there was a little girl named Lily. She loved to play outside" ...
279-
# QNN libnative may print an initialization message to stdout before the generated text.
280-
if grep -qF -- "${EXPECTED_PREFIX}" result.txt; then
279+
if [[ "${RESULT}" == "${EXPECTED_PREFIX}"* ]]; then
281280
echo "Expected result prefix: ${EXPECTED_PREFIX}"
282281
echo "Actual result: ${RESULT}"
283282
echo "Success"
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/usr/bin/env python
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
"""Assemble part of a CUDA toolkit from NVIDIA's redistributable component archives.
9+
10+
The Windows CUDA wheel end-to-end jobs cover several CUDA trains while the CI images carry
11+
one toolkit, and NVIDIA publishes no full Windows installer for every release. The redist
12+
archives exist for every release on both platforms, need no installer or admin rights, and
13+
are checksummed in a JSON index. Merging the components a job needs into one directory
14+
gives the layout nvcc, CMake's FindCUDAToolkit and torch's cross-compile step expect.
15+
16+
install_cuda_redist.py --train 13.4 --platform linux-x86_64 --dest /opt/cuda-13.4
17+
install_cuda_redist.py --train 13.4 --platform windows-x86_64 --dest DIR --components cuda_cudart
18+
"""
19+
20+
import argparse
21+
import hashlib
22+
import json
23+
import shutil
24+
import sys
25+
import tarfile
26+
import tempfile
27+
import urllib.request
28+
import zipfile
29+
from pathlib import Path
30+
31+
_REDIST = "https://developer.download.nvidia.com/compute/cuda/redist"
32+
33+
# The patch release each train resolves to: one entry per train in filter_cuda_matrix.py's
34+
# SUPPORTED_CUDA_VERSIONS, which the end-to-end jobs take their matrix from, and 13.0, which
35+
# is no longer published but still builds from source and is what local tests of it use. A
36+
# train missing here fails the job at argument parsing rather than testing a different
37+
# release.
38+
_RELEASES = {"13.0": "13.0.2", "13.2": "13.2.2", "13.4": "13.4.1"}
39+
40+
# What a build of the CUDA backend needs. "a|b" names one component a release publishes
41+
# under either name (CCCL was renamed between releases).
42+
_BUILD_COMPONENTS = [
43+
"cuda_nvcc",
44+
"cuda_cudart",
45+
"cuda_crt",
46+
"cccl|cuda_cccl",
47+
"libnvvm",
48+
"cuda_cuobjdump",
49+
"cuda_nvrtc",
50+
"cuda_profiler_api",
51+
"cuda_nvtx",
52+
# rand.cu includes curand_kernel.h.
53+
"libcurand",
54+
]
55+
56+
57+
def _fetch(url: str, destination: Path) -> None:
58+
with urllib.request.urlopen(url, timeout=300) as response, open(
59+
destination, "wb"
60+
) as handle:
61+
shutil.copyfileobj(response, handle)
62+
63+
64+
def _extract(archive: Path, into: Path) -> Path:
65+
if archive.suffix == ".zip":
66+
with zipfile.ZipFile(archive) as bundle:
67+
bundle.extractall(into)
68+
else:
69+
with tarfile.open(archive) as bundle:
70+
if hasattr(tarfile, "fully_trusted_filter"):
71+
bundle.extractall(into, filter="fully_trusted")
72+
else:
73+
bundle.extractall(into)
74+
# Each archive holds one top-level directory named after itself.
75+
(top,) = [entry for entry in into.iterdir() if entry.is_dir()]
76+
return top
77+
78+
79+
def main() -> None:
80+
parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
81+
parser.add_argument("--train", required=True, choices=sorted(_RELEASES))
82+
parser.add_argument(
83+
"--platform", required=True, choices=["linux-x86_64", "windows-x86_64"]
84+
)
85+
parser.add_argument("--dest", required=True, type=Path)
86+
parser.add_argument("--components", nargs="+", default=_BUILD_COMPONENTS)
87+
arguments = parser.parse_args()
88+
89+
release = _RELEASES[arguments.train]
90+
with urllib.request.urlopen(
91+
f"{_REDIST}/redistrib_{release}.json", timeout=120
92+
) as response:
93+
index = json.load(response)
94+
arguments.dest.mkdir(parents=True, exist_ok=True)
95+
with tempfile.TemporaryDirectory() as work:
96+
work = Path(work)
97+
for choice in arguments.components:
98+
names = [
99+
name
100+
for name in choice.split("|")
101+
if arguments.platform in index.get(name, {})
102+
]
103+
if not names:
104+
sys.exit(
105+
f"CUDA {release} publishes none of {choice} for {arguments.platform}"
106+
)
107+
entry = index[names[0]][arguments.platform]
108+
archive = work / Path(entry["relative_path"]).name
109+
_fetch(f"{_REDIST}/{entry['relative_path']}", archive)
110+
digest = hashlib.sha256(archive.read_bytes()).hexdigest()
111+
if digest != entry["sha256"]:
112+
sys.exit(f"checksum mismatch for {archive.name}")
113+
staging = work / "staging"
114+
top = _extract(archive, staging)
115+
shutil.copytree(top, arguments.dest, symlinks=True, dirs_exist_ok=True)
116+
shutil.rmtree(staging)
117+
archive.unlink()
118+
print(
119+
f"merged {names[0]} {index[names[0]]['version']} into {arguments.dest}"
120+
)
121+
# The Linux archives keep libraries in lib/, while nvcc's link step and CMake's
122+
# FindCUDAToolkit look in lib64/, which is where an installed toolkit has them.
123+
lib, lib64 = arguments.dest / "lib", arguments.dest / "lib64"
124+
if arguments.platform == "linux-x86_64" and lib.is_dir() and not lib64.exists():
125+
lib64.symlink_to("lib", target_is_directory=True)
126+
127+
128+
if __name__ == "__main__":
129+
main()

‎.ci/scripts/wheel/pre_build_script.sh‎

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,23 @@ else
116116
export CMAKE_ARGS="${CMAKE_ARGS:-} -DEXECUTORCH_BUILD_CUDA=ON"
117117
echo "CMAKE_ARGS=${CMAKE_ARGS}" >> "${GITHUB_ENV}"
118118
echo "row '${CU_VERSION:-${DESIRED_CUDA:-}}' is a CUDA row, requiring the CUDA build"
119+
# The Linux rows take the row's GPU list from envvar_cuda_linux.sh. Windows has no env-var
120+
# script slot, so the same list is resolved here; without it the build compiles device
121+
# code only for whatever GPU the builder has. The reusable workflow writes its own list
122+
# into BUILD_ENV_FILE, which the build step sources after this hook and which would
123+
# otherwise win, so the row's list is appended there as well as to GITHUB_ENV.
124+
# Also needed for the ninja the Windows CUDA build generates with.
125+
if [[ $UNAME_S == *"MINGW"* || $UNAME_S == *"MSYS"* ]]; then
126+
source "${GITHUB_WORKSPACE}/${REPOSITORY}/.ci/scripts/wheel/cuda_arch_list.sh"
127+
TORCH_CUDA_ARCH_LIST="$(EXECUTORCH_BUILD_CUDA=1 executorch_cuda_arch_list)"
128+
export TORCH_CUDA_ARCH_LIST
129+
echo "TORCH_CUDA_ARCH_LIST=${TORCH_CUDA_ARCH_LIST}" >> "${GITHUB_ENV}"
130+
if [[ -n "${BUILD_ENV_FILE:-}" ]]; then
131+
echo "export TORCH_CUDA_ARCH_LIST='${TORCH_CUDA_ARCH_LIST}'" >> "${BUILD_ENV_FILE}"
132+
fi
133+
echo "building device code for: ${TORCH_CUDA_ARCH_LIST}"
134+
pip install --quiet ninja
135+
fi
119136
fi
120137

121138
# On Windows, enable symlinks and re-checkout the current revision to create
@@ -125,14 +142,6 @@ if [[ $UNAME_S == *"MINGW"* || $UNAME_S == *"MSYS"* ]]; then
125142
git config core.symlinks true
126143
git checkout -f HEAD
127144

128-
# Windows wheels are CPU-only (build-wheels-windows.yml sets
129-
# with-cuda: disabled), but the Windows CI image ships a CUDA toolkit on
130-
# PATH, which makes setup.py auto-enable EXECUTORCH_BUILD_CUDA. That bakes a
131-
# CUDA _C into the CPU wheel, which then fails its DLL load in the
132-
# smoke test ("DLL load failed while importing _C"). Force a
133-
# CPU-only build.
134-
export CMAKE_ARGS="${CMAKE_ARGS:-} -DEXECUTORCH_BUILD_CUDA=OFF"
135-
echo "CMAKE_ARGS=${CMAKE_ARGS}" >> "${GITHUB_ENV}"
136145
fi
137146

138147
# Manually install build requirements because `python setup.py bdist_wheel` does
@@ -202,7 +211,8 @@ if [[ "${EXECUTORCH_BUILD_VULKAN:-0}" != "0" \
202211
echo "glslc installed: $(command -v glslc)"
203212
fi
204213
else
205-
# This is the Vulkan equivalent of the Windows CUDA force-off above (#20527).
214+
# Off unless asked for: a builder with the Vulkan SDK would otherwise turn it on
215+
# for a wheel that does not ship it, as a CUDA toolkit once did for Windows (#20527).
206216
export CMAKE_ARGS="${CMAKE_ARGS:-} -DEXECUTORCH_BUILD_VULKAN=OFF"
207217
echo "CMAKE_ARGS=${CMAKE_ARGS}" >> "${GITHUB_ENV}"
208218
fi

‎.ci/scripts/wheel/test_cpp_sdk.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,11 +1741,13 @@ def test_pre_3_28_route_builds_a_consumer_through_variables(work_dir: Path) -> N
17411741
"target_link_libraries(consumer PRIVATE ${EXECUTORCH_LIBRARIES})\n"
17421742
"set_target_properties(consumer PROPERTIES CXX_STANDARD ${EXECUTORCH_CXX_STANDARD})\n"
17431743
# No imported targets on this route, so no TARGET_RUNTIME_DLLS either. A Windows
1744-
# consumer copies the DLLs from the directory the package reports.
1744+
# consumer copies the DLLs from the directory the package reports, plus any the
1745+
# package lists separately because they ship elsewhere.
17451746
"if(WIN32)\n"
17461747
' file(GLOB _dlls "${EXECUTORCH_RUNTIME_LIBRARY_DIR}/*.dll")\n'
17471748
" add_custom_command(TARGET consumer POST_BUILD COMMAND ${CMAKE_COMMAND} -E "
1748-
"copy_if_different ${_dlls} $<TARGET_FILE_DIR:consumer>)\n"
1749+
"copy_if_different ${_dlls} ${EXECUTORCH_RUNTIME_DLLS_EXTRA} "
1750+
"$<TARGET_FILE_DIR:consumer>)\n"
17491751
"endif()\n"
17501752
)
17511753
build_dir = work_dir / "pre-328-build"

0 commit comments

Comments
 (0)