Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .devops/cuda.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ ARG BASE_CUDA_RUN_CONTAINER=docker.io/nvidia/cuda:${CUDA_VERSION}-runtime-ubuntu
FROM ${BASE_CUDA_DEV_CONTAINER} AS build

ARG GCC_VERSION=14
# CUDA architectures to compile for.
# - default = the portable default list from CMakeLists.txt
# - for a custom arch set build with --build-arg CUDA_DOCKER_ARCH="89-real;...".
ARG CUDA_DOCKER_ARCH=default

# Install build toolchain
RUN apt-get update && \
Expand All @@ -30,8 +34,10 @@ ENV CC=gcc-${GCC_VERSION} CXX=g++-${GCC_VERSION} CUDAHOSTCXX=g++-${GCC_VERSION}
WORKDIR /app
COPY . .

# Configure and build
RUN cmake -S . -B build \
RUN if [ "${CUDA_DOCKER_ARCH}" != "default" ]; then \
ADDITIONAL_CMAKE_ARGS="-DCMAKE_CUDA_ARCHITECTURES=${CUDA_DOCKER_ARCH}"; \
fi && \
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DAUDIOCPP_MODEL_SET=full \
-DENGINE_ENABLE_CPU_ALL_VARIANTS=ON \
Expand All @@ -43,6 +49,7 @@ RUN cmake -S . -B build \
-DENGINE_BUILD_EXAMPLES=OFF \
-DENGINE_BUILD_TESTS=OFF \
-DENGINE_BUILD_WARMBENCH=OFF \
${ADDITIONAL_CMAKE_ARGS} \
-DCMAKE_EXE_LINKER_FLAGS=-Wl,--allow-shlib-undefined && \
cmake --build build --parallel $(nproc) \
--target audiocpp_cli \
Expand Down
82 changes: 67 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,74 @@ if (ENGINE_HIP_STRIX_HALO_OPTIMIZATIONS)
endif()

if (ENGINE_ENABLE_CUDA AND NOT ENGINE_ENABLE_HIP)
enable_language(CUDA)
# 12.0 is a floor, not a target: any 12.x or 13.x works (the Dockerfile pins
# 12.9.0, and docs/build/windows.md ships a CUDA 13 package). The minimum is
# enforced because an older toolkit configures happily and only fails at the
# first .cu file, which reads as a code bug rather than a toolchain one: nvcc
# < 11.6 cannot parse libstdc++ >= 11.3 headers ("parameter packs not expanded
# with '...'" in <functional>), and distros still ship such pairings (Ubuntu
# 22.04's nvidia-cuda-toolkit is 11.5). Fail here, with a pointer, instead.
# The upper bound is the host compiler the chosen toolkit accepts, not CUDA
# itself (e.g. CUDA 12.9 supports GCC <= 14), so it is left to the toolkit.
# Require at least CUDA 12.0. Older toolkits configure fine but die at the
# first .cu file. Run this before enable_language(CUDA) because the version
# is needed for the default arch list below.
find_package(CUDAToolkit 12.0 REQUIRED)

# Define default CUDA architectures for every build path.
# We stay close to llama.cpp/ggml-cuda here, unless there is a reason
# to deviate. See llama.cpp's ggml-cuda CMakeLists.txt for additional
# comments.
# Must be set before enable_language(CUDA), as that call otherwise seeds
# CMAKE_CUDA_ARCHITECTURES from nvcc's default arch (sm_75 for CUDA 13,
# sm_52 for CUDA 12), silently making every build without an explicit
# list single-arch (the seed ignores the local GPU).
# This can be overridden with -DCMAKE_CUDA_ARCHITECTURES=... or CUDAARCHS;
# set to "native" to build for the local GPU only (needs CMake >= 3.24).

# "native" fallback for CMake < 3.24
if ((CMAKE_CUDA_ARCHITECTURES STREQUAL "native" OR "$ENV{CUDAARCHS}" STREQUAL "native")
AND CMAKE_VERSION VERSION_LESS "3.24")
message(STATUS "CMAKE_CUDA_ARCHITECTURES=native requires CMake >= 3.24; "
"falling back to the portable default architecture list")
set(CMAKE_CUDA_ARCHITECTURES "")
endif()

# Define default archs
if ("${CMAKE_CUDA_ARCHITECTURES}" STREQUAL "" AND "$ENV{CUDAARCHS}" STREQUAL "")
# XX-virtual = PTX (JIT, forward-compatible); XX-real = SASS (native).
if (CUDAToolkit_VERSION VERSION_LESS "13")
# 50/61/70 (Maxwell/Pascal/Volta) unsupported by CUDA 13 toolkits
list(APPEND CMAKE_CUDA_ARCHITECTURES 50-virtual 61-virtual 70-virtual)
endif()
list(APPEND CMAKE_CUDA_ARCHITECTURES 75-virtual 80-virtual 86-real)
if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "11.8")
list(APPEND CMAKE_CUDA_ARCHITECTURES 89-real 90-virtual)
endif()
if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.8")
# 12Xa, not 12X: Blackwell FP4 tensor cores are arch-specific.
list(APPEND CMAKE_CUDA_ARCHITECTURES 120a-real)
endif()
if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.9")
list(APPEND CMAKE_CUDA_ARCHITECTURES 121a-real)
endif()
endif()

enable_language(CUDA)

# Upgrade plain 12X (user value or resolved "native") to 12Xa (Blackwell).
foreach (_ARCHS_VAR IN ITEMS CMAKE_CUDA_ARCHITECTURES CMAKE_CUDA_ARCHITECTURES_NATIVE)
set(_FIXED_ARCHS "")
foreach (_ARCH IN LISTS ${_ARCHS_VAR})
if (_ARCH MATCHES "^12[0-9](-real|-virtual)?$")
string(REGEX REPLACE "^(12[0-9])((-real|-virtual)?)$" "\\1a\\2" _FIXED_ARCH "${_ARCH}")
message(STATUS "Replacing ${_ARCH} in ${_ARCHS_VAR} with ${_FIXED_ARCH}")
list(APPEND _FIXED_ARCHS "${_FIXED_ARCH}")
else()
list(APPEND _FIXED_ARCHS "${_ARCH}")
endif()
endforeach()
set(${_ARCHS_VAR} "${_FIXED_ARCHS}")
endforeach()

# Resolve "native" for the log; left as-is when no GPU was detected
# (nvcc then warns and uses its default arch).
if (CMAKE_CUDA_ARCHITECTURES STREQUAL "native" AND CMAKE_CUDA_ARCHITECTURES_NATIVE MATCHES "^[0-9]+(a|f)?(-real|-virtual)?(;[0-9]+(a|f)?(-real|-virtual)?|;)*$")
set(CMAKE_CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES_NATIVE}")
endif()
message(STATUS "Using CMAKE_CUDA_ARCHITECTURES=${CMAKE_CUDA_ARCHITECTURES} CMAKE_CUDA_ARCHITECTURES_NATIVE=${CMAKE_CUDA_ARCHITECTURES_NATIVE}")

if (NOT MSVC)
set(CMAKE_CUDA_FLAGS_DEBUG "${AUDIOCPP_DEBUG_OPT_FLAGS}" CACHE STRING "Optimized debug CUDA flags" FORCE)
endif()
Expand Down Expand Up @@ -1472,11 +1529,6 @@ if (ENGINE_ENABLE_CUDA AND NOT ENGINE_ENABLE_HIP)
CUDA_STANDARD 17
CUDA_STANDARD_REQUIRED ON
)
if (CMAKE_CUDA_ARCHITECTURES)
set_target_properties(engine_runtime PROPERTIES CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}")
else()
set_target_properties(engine_runtime PROPERTIES CUDA_ARCHITECTURES native)
endif()
target_compile_definitions(engine_core PRIVATE ENGINE_HAS_CUDA_ISTFT=1 ENGINE_HAS_CUDA_TORCH_RANDOM=1)
target_compile_definitions(engine_runtime PUBLIC ENGINE_HAS_CUDA_ISTFT=1 ENGINE_HAS_CUDA_TORCH_RANDOM=1)
target_link_libraries(engine_runtime PRIVATE CUDA::cudart CUDA::cufft)
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ scripts/build_linux.sh --backend cpu --target audiocpp_cli --target audiocpp_ser

The script writes to aligned build directories such as `build/linux-cuda-release`, `build/linux-vulkan-release`, `build/linux-hip-release`, and `build/linux-cpu-release`.

Without `--cuda-arch`, CUDA builds use the portable arch list (works on many
GPUs, slower to build). For a faster build targeting only the local GPU, pass
`--cuda-arch native` (CMake >= 3.24; on older CMake this falls back to the
portable list) or an explicit arch list:

```bash
scripts/build_linux.sh --backend cuda --cuda-arch native --target audiocpp_cli --target audiocpp_server
scripts/build_linux.sh --backend cuda --cuda-arch "86;89" --target audiocpp_cli --target audiocpp_server
```

Composite examples:

```bash
Expand Down
28 changes: 14 additions & 14 deletions docs/build/linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ CUDA:
cmake -S . -B build -DENGINE_ENABLE_CUDA=ON
```

Without `CMAKE_CUDA_ARCHITECTURES`, the portable default arch list is built:
works on many GPUs, but builds slower. To build only for the local GPUs,
`native` is recommended (CMake >= 3.24; on older CMake it falls back to the
portable list) or set an arch manually.

```bash
cmake -S . -B build -DENGINE_ENABLE_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=native
```

CMake picks the first `nvcc` on `PATH`, which is often **not** the toolkit you want:
distro packages install an old one to `/usr/bin/nvcc` (Ubuntu 22.04's
`nvidia-cuda-toolkit` is CUDA 11.5) while the toolkit from NVIDIA lands in
Expand All @@ -54,20 +63,11 @@ readelf -d build/bin/audiocpp_server | grep NEEDED | grep cuda
# want libcudart.so.12 / libcublas.so.12 — libcudart.so.11.0 means a mixed build
```

Leaving `CMAKE_CUDA_ARCHITECTURES` unset does **not** reliably build for the GPUs
present at build time on this codebase, even though ggml's own `ggml-cuda/CMakeLists.txt`
implements exactly that native-detect fallback. The reason: this project's top-level
`CMakeLists.txt` calls `enable_language(CUDA)` itself, before ggml's subdirectory is
processed — CMake computes its own default `CMAKE_CUDA_ARCHITECTURES` at that point, so
ggml's fallback logic (gated on the variable still being undefined) never runs. Verified
directly: on an RTX 5060 (sm_120), leaving the flag unset made CMake default to bare `75`
(Turing) even though `CMAKE_CUDA_ARCHITECTURES_NATIVE` was correctly autodetected as
`120a-real` in the same configure log — computed but never used. Any
`__CUDA_ARCH__`-gated kernel path newer than the default silently compiles *out*, not
merely unoptimized. **Always pass `CMAKE_CUDA_ARCHITECTURES` explicitly.**

Note that CMake caches the CUDA compiler: switching toolkits in an
existing build directory requires deleting `CMakeCache.txt` and `CMakeFiles/`.
Leave `CMAKE_CUDA_ARCHITECTURES` unset to build the portable default arch list
(works on many GPUs, slower to build); set it to `native` (CMake >= 3.24) to
build only for the GPUs present at build time. Note that CMake caches the CUDA
compiler: switching toolkits in an existing build directory requires deleting
`CMakeCache.txt` and `CMakeFiles/`.


Old CUDA GPUs (cm<89):
Expand Down
6 changes: 6 additions & 0 deletions docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ Build with a specific CUDA version, for example 13.3.0:
docker build -f .devops/cuda.Dockerfile -t local/audio.cpp:full-cuda13 --build-arg CUDA_VERSION=13.3.0 .
```

Build for a specific set of GPU architectures (e.g. for faster, less portable builds):

```bash
docker build -f .devops/cuda.Dockerfile -t local/audio.cpp:full-cuda12 --build-arg CUDA_DOCKER_ARCH="86;89" .
```

### CPU

```bash
Expand Down
2 changes: 1 addition & 1 deletion scripts/build_linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ echo "Using generator: $GENERATOR"
echo "Using build dir: $BUILD_DIR"
echo "Including CUDA backend: $ENGINE_ENABLE_CUDA"
if [[ "$ENGINE_ENABLE_CUDA" == "ON" ]]; then
echo "CUDA architectures: ${CUDA_ARCH:-<auto: machine-native at configure time>}"
echo "CUDA architectures: ${CUDA_ARCH:-<portable default list>}"
fi
echo "Including Vulkan backend: $ENGINE_ENABLE_VULKAN"
echo "Including HIP backend: $ENGINE_ENABLE_HIP"
Expand Down
Loading