| 1 | include(FetchContent) |
| 2 | |
| 3 | set(CUTLASS_INCLUDE_DIR "${CUTLASS_INCLUDE_DIR}" CACHE PATH "Path to CUTLASS include/ directory") |
| 4 | |
| 5 | if(DEFINED ENV{QUTLASS_SRC_DIR}) |
| 6 | set(QUTLASS_SRC_DIR $ENV{QUTLASS_SRC_DIR}) |
| 7 | endif() |
| 8 | |
| 9 | # CMP0169 NEW: one-argument FetchContent_Populate(name) after Declare is invalid. |
| 10 | # Use explicit Populate(...) for git, or set SOURCE_DIR for local trees. |
| 11 | if(QUTLASS_SRC_DIR) |
| 12 | set(_qutlass_user_src "${QUTLASS_SRC_DIR}") |
| 13 | cmake_path(ABSOLUTE_PATH _qutlass_user_src |
| 14 | BASE_DIRECTORY "${CMAKE_SOURCE_DIR}" |
| 15 | NORMALIZE) |
| 16 | set(QUTLASS_SRC_DIR "${_qutlass_user_src}") |
| 17 | if(NOT IS_DIRECTORY "${QUTLASS_SRC_DIR}") |
| 18 | message(FATAL_ERROR |
| 19 | "[QUTLASS] QUTLASS_SRC_DIR is not an existing directory: '${QUTLASS_SRC_DIR}'") |
| 20 | endif() |
| 21 | set(qutlass_SOURCE_DIR "${QUTLASS_SRC_DIR}") |
| 22 | set(qutlass_BINARY_DIR "${CMAKE_BINARY_DIR}/qutlass-binary-dir-unused") |
| 23 | else() |
| 24 | set(_QUTLASS_UPSTREAM_REPO "https://github.com/IST-DASLab/qutlass.git") |
| 25 | set(_QUTLASS_UPSTREAM_TAG "e74319e3405ce6d71965732880f5dc1f52371f64") |
| 26 | |
| 27 | set(_qutlass_fc_root "${FETCHCONTENT_BASE_DIR}") |
| 28 | if(NOT _qutlass_fc_root) |
| 29 | set(_qutlass_fc_root "${CMAKE_BINARY_DIR}/_deps") |
| 30 | endif() |
| 31 | set(_qutlass_src "${_qutlass_fc_root}/qutlass-src") |
| 32 | set(_qutlass_bin "${_qutlass_fc_root}/qutlass-build") |
| 33 | set(_qutlass_sub "${_qutlass_fc_root}/qutlass-subbuild") |
| 34 | |
| 35 | if(EXISTS "${_qutlass_src}/qutlass/csrc/bindings.cpp") |
| 36 | set(qutlass_SOURCE_DIR "${_qutlass_src}") |
| 37 | set(qutlass_BINARY_DIR "${_qutlass_bin}") |
| 38 | else() |
| 39 | FetchContent_Populate( |
| 40 | qutlass |
| 41 | SUBBUILD_DIR "${_qutlass_sub}" |
| 42 | SOURCE_DIR "${_qutlass_src}" |
| 43 | BINARY_DIR "${_qutlass_bin}" |
| 44 | GIT_REPOSITORY "${_QUTLASS_UPSTREAM_REPO}" |
| 45 | GIT_TAG "${_QUTLASS_UPSTREAM_TAG}" |
| 46 | GIT_PROGRESS TRUE |
| 47 | ) |
| 48 | endif() |
| 49 | endif() |
| 50 | |
| 51 | if(NOT qutlass_SOURCE_DIR) |
| 52 | message(FATAL_ERROR "[QUTLASS] source directory could not be resolved.") |
| 53 | endif() |
| 54 | message(STATUS "[QUTLASS] QuTLASS is available at ${qutlass_SOURCE_DIR}") |
| 55 | |
| 56 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 13.0) |
| 57 | cuda_archs_loose_intersection(QUTLASS_SM120_ARCHS "12.0f" "${CUDA_ARCHS}") |
| 58 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 13.4) |
| 59 | cuda_archs_loose_intersection(QUTLASS_SM100_ARCHS "10.0f;10.7f" "${CUDA_ARCHS}") |
| 60 | else() |
| 61 | cuda_archs_loose_intersection(QUTLASS_SM100_ARCHS "10.0f" "${CUDA_ARCHS}") |
| 62 | endif() |
| 63 | else() |
| 64 | cuda_archs_loose_intersection(QUTLASS_SM120_ARCHS "12.0a;12.1a" "${CUDA_ARCHS}") |
| 65 | cuda_archs_loose_intersection(QUTLASS_SM100_ARCHS "10.0a;10.3a" "${CUDA_ARCHS}") |
| 66 | endif() |
| 67 | |
| 68 | # QUTLASS uses TARGET_CUDA_ARCH as a single preprocessor selector for all its |
| 69 | # sources. Do not compile a mixed SM100/SM120 arch list with one selector; prefer |
| 70 | # SM100 when both families are requested because that is the primary deployed |
| 71 | # target for this extension today. |
| 72 | if(QUTLASS_SM100_ARCHS) |
| 73 | set(QUTLASS_ARCHS "${QUTLASS_SM100_ARCHS}") |
| 74 | set(QUTLASS_TARGET_CC 100) |
| 75 | if(QUTLASS_SM120_ARCHS) |
| 76 | message(WARNING |
| 77 | "[QUTLASS] Both SM100 and SM120 archs were requested; selecting SM100 " |
| 78 | "because TARGET_CUDA_ARCH is a single compile-time selector.") |
| 79 | endif() |
| 80 | elseif(QUTLASS_SM120_ARCHS) |
| 81 | set(QUTLASS_ARCHS "${QUTLASS_SM120_ARCHS}") |
| 82 | set(QUTLASS_TARGET_CC 120) |
| 83 | else() |
| 84 | set(QUTLASS_ARCHS) |
| 85 | endif() |
| 86 | |
| 87 | if(${CMAKE_CUDA_COMPILER_VERSION} VERSION_GREATER_EQUAL 12.8 AND QUTLASS_ARCHS) |
| 88 | set(QUTLASS_SOURCES |
| 89 | csrc/qutlass_registration.cpp |
| 90 | ${qutlass_SOURCE_DIR}/qutlass/csrc/bindings.cpp |
| 91 | ${qutlass_SOURCE_DIR}/qutlass/csrc/gemm.cu |
| 92 | ${qutlass_SOURCE_DIR}/qutlass/csrc/gemm_ada.cu |
| 93 | ${qutlass_SOURCE_DIR}/qutlass/csrc/fused_quantize_mx.cu |
| 94 | ${qutlass_SOURCE_DIR}/qutlass/csrc/fused_quantize_nv.cu |
| 95 | ${qutlass_SOURCE_DIR}/qutlass/csrc/fused_quantize_mx_sm100.cu |
| 96 | ${qutlass_SOURCE_DIR}/qutlass/csrc/fused_quantize_nv_sm100.cu |
| 97 | ) |
| 98 | |
| 99 | set(QUTLASS_INCLUDES |
| 100 | ${qutlass_SOURCE_DIR} |
| 101 | ${qutlass_SOURCE_DIR}/qutlass |
| 102 | ${qutlass_SOURCE_DIR}/qutlass/csrc/include |
| 103 | ${qutlass_SOURCE_DIR}/qutlass/csrc/include/cutlass_extensions |
| 104 | ) |
| 105 | |
| 106 | if(CUTLASS_INCLUDE_DIR AND EXISTS "${CUTLASS_INCLUDE_DIR}/cutlass/cutlass.h") |
| 107 | list(APPEND QUTLASS_INCLUDES "${CUTLASS_INCLUDE_DIR}") |
| 108 | if(CUTLASS_TOOLS_UTIL_INCLUDE_DIR AND |
| 109 | EXISTS "${CUTLASS_TOOLS_UTIL_INCLUDE_DIR}/cutlass/util/packed_stride.hpp") |
| 110 | list(APPEND QUTLASS_INCLUDES "${CUTLASS_TOOLS_UTIL_INCLUDE_DIR}") |
| 111 | else() |
| 112 | get_filename_component(_qutlass_cutlass_root "${CUTLASS_INCLUDE_DIR}" DIRECTORY) |
| 113 | if(EXISTS "${_qutlass_cutlass_root}/tools/util/include/cutlass/util/packed_stride.hpp") |
| 114 | list(APPEND QUTLASS_INCLUDES "${_qutlass_cutlass_root}/tools/util/include") |
| 115 | endif() |
| 116 | endif() |
| 117 | elseif(EXISTS "${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/include/cutlass/cutlass.h") |
| 118 | list(APPEND QUTLASS_INCLUDES |
| 119 | "${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/include" |
| 120 | "${qutlass_SOURCE_DIR}/qutlass/third_party/cutlass/tools/util/include") |
| 121 | message(STATUS "[QUTLASS] Using QuTLASS vendored CUTLASS headers (no vLLM CUTLASS detected).") |
| 122 | else() |
| 123 | message(FATAL_ERROR "[QUTLASS] CUTLASS headers not found. " |
| 124 | "Set -DCUTLASS_INCLUDE_DIR=/path/to/cutlass/include") |
| 125 | endif() |
| 126 | |
| 127 | set_gencode_flags_for_srcs( |
| 128 | SRCS "${QUTLASS_SOURCES}" |
| 129 | CUDA_ARCHS "${QUTLASS_ARCHS}" |
| 130 | ) |
| 131 | |
| 132 | define_extension_target( |
| 133 | _qutlass_C |
| 134 | DESTINATION vllm |
| 135 | LANGUAGE ${VLLM_GPU_LANG} |
| 136 | SOURCES ${QUTLASS_SOURCES} |
| 137 | COMPILE_FLAGS ${VLLM_GPU_FLAGS} |
| 138 | ARCHITECTURES ${VLLM_GPU_ARCHES} |
| 139 | INCLUDE_DIRECTORIES ${QUTLASS_INCLUDES} |
| 140 | USE_SABI 3 |
| 141 | WITH_SOABI) |
| 142 | |
| 143 | target_compile_definitions(_qutlass_C PRIVATE |
| 144 | QUTLASS_MINIMAL_BUILD=1 |
| 145 | QUTLASS_DISABLE_PYBIND=1 |
| 146 | TARGET_CUDA_ARCH=${QUTLASS_TARGET_CC} |
| 147 | CUTLASS_ENABLE_DIRECT_CUDA_DRIVER_CALL=1 |
| 148 | USE_CUDA) |
| 149 | |
| 150 | set_property(SOURCE ${QUTLASS_SOURCES} APPEND PROPERTY COMPILE_OPTIONS |
| 151 | $<$<COMPILE_LANGUAGE:CUDA>:--expt-relaxed-constexpr --use_fast_math -O3> |
| 152 | ) |
| 153 | |
| 154 | else() |
| 155 | if("${CMAKE_CUDA_COMPILER_VERSION}" VERSION_LESS "12.8") |
| 156 | message(STATUS |
| 157 | "[QUTLASS] Skipping build: CUDA 12.8 or newer is required (found ${CMAKE_CUDA_COMPILER_VERSION}).") |
| 158 | else() |
| 159 | message(STATUS |
| 160 | "[QUTLASS] Skipping build: no supported arch (12.0f / 10.0f) found in " |
| 161 | "CUDA_ARCHS='${CUDA_ARCHS}'.") |
| 162 | endif() |
| 163 | add_custom_target(_qutlass_C) |
| 164 | endif() |