File size: 8,945 Bytes
9425aed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
cmake_minimum_required(VERSION 3.20)
project(sov_rtx LANGUAGES C)

option(SOV_BUILD_CUDA "Enable PTX validation targets" ON)
if(WIN32 AND CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
    set(SOV_ZERO_LIBC_DEFAULT ON)
else()
    set(SOV_ZERO_LIBC_DEFAULT OFF)
endif()
option(SOV_ZERO_LIBC
    "Build the supported GNU/Clang zero-CRT Windows entry point"
    ${SOV_ZERO_LIBC_DEFAULT})
option(SOV_BUILD_FORTRAN_REFERENCE
    "Build the optional Fortran 2018 transformer reference" OFF)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

set(SOV_PTX_DIR       "${CMAKE_CURRENT_SOURCE_DIR}/src/cuda")
set(SOV_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(SOV_PTX_BLOB_SOURCE "${SOV_GENERATED_DIR}/sov_ptx_blobs.c")
file(MAKE_DIRECTORY "${SOV_GENERATED_DIR}")

# Convert PTX bytes to a C array at configure time. The final zero byte is
# included in both the array and *_len so every loader can validate the
# complete bounded text-image contract before calling cuModuleLoadData.
function(sov_ptx_to_c_source input_path symbol output_variable)
    if(NOT EXISTS "${input_path}")
        message(FATAL_ERROR "Required PTX source is missing: ${input_path}")
    endif()
    set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${input_path}")
    file(READ "${input_path}" ptx_text)
    if(ARGC GREATER 3)
        string(REGEX REPLACE "\\.target[ \t]+sm_[0-9]+"
               ".target ${ARGV3}" ptx_text "${ptx_text}")
    endif()
    string(HEX "${ptx_text}" ptx_hex)
    string(LENGTH "${ptx_hex}" ptx_hex_length)
    if(ptx_hex_length EQUAL 0)
        message(FATAL_ERROR "PTX source is empty: ${input_path}")
    endif()
    math(EXPR ptx_byte_count  "${ptx_hex_length} / 2")
    math(EXPR ptx_buffer_size "${ptx_byte_count} + 1")
    math(EXPR ptx_last_offset "${ptx_hex_length} - 2")
    set(generated_text "const unsigned char ${symbol}[] = {\n    ")
    set(bytes_on_line 0)
    foreach(offset RANGE 0 ${ptx_last_offset} 2)
        string(SUBSTRING "${ptx_hex}" ${offset} 2 byte_hex)
        string(APPEND generated_text "0x${byte_hex},")
        math(EXPR bytes_on_line "${bytes_on_line} + 1")
        if(bytes_on_line EQUAL 16)
            string(APPEND generated_text "\n    ")
            set(bytes_on_line 0)
        endif()
    endforeach()
    string(APPEND generated_text
        "0x00\n};\n"
        "const unsigned int ${symbol}_len = ${ptx_buffer_size}u;\n")
    set(${output_variable} "${generated_text}" PARENT_SCOPE)
endfunction()

sov_ptx_to_c_source("${SOV_PTX_DIR}/flash_attention.ptx"
                    flash_attention_ptx flash_ptx_source)
sov_ptx_to_c_source("${SOV_PTX_DIR}/gemm.ptx"
                    gemm_ptx gemm_ptx_source)
file(WRITE "${SOV_PTX_BLOB_SOURCE}"
    "/* Generated by CMake. Do not edit. */\n"
    "${flash_ptx_source}\n"
    "${gemm_ptx_source}\n")

add_library(sov_rtx STATIC
    src/loader/gguf.c
    src/kv_allocator.c
    src/sampler.c
    src/cuda_validation_chain.c
    src/rowm_cuda_validation.c
    src/cuda_gemm_dispatch.c
    src/cuda_kernels.c
    windows_rtx/cuda_driver_loader.c
    windows_rtx/power_handler.c
    "${SOV_PTX_BLOB_SOURCE}"
)
target_include_directories(sov_rtx PUBLIC include PRIVATE src)

if(SOV_BUILD_FORTRAN_REFERENCE)
    enable_language(Fortran)
    add_library(sov_rtx_fortran_reference STATIC
        src/fortran/transformer_kernel.f90)
    set_property(TARGET sov_rtx_fortran_reference PROPERTY Fortran_STANDARD 2018)
    set_property(TARGET sov_rtx_fortran_reference PROPERTY Fortran_STANDARD_REQUIRED ON)
endif()

if(SOV_ZERO_LIBC)
    if(NOT WIN32)
        message(FATAL_ERROR "SOV_ZERO_LIBC is supported only on Windows")
    endif()
    if(MSVC OR NOT CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
        message(FATAL_ERROR
            "SOV_ZERO_LIBC currently requires GNU or Clang because main.c "
            "uses that compiler family's x86-64 inline assembly")
    endif()
    target_compile_options(sov_rtx PRIVATE
        -ffreestanding -fno-builtin -fno-stack-protector)
    add_executable(sov_main windows_rtx/main.c)
    target_link_libraries(sov_main PRIVATE sov_rtx)
    target_compile_options(sov_main PRIVATE
        -ffreestanding -fno-builtin -fno-stack-protector)
    target_link_options(sov_main PRIVATE -nostdlib -Wl,--entry=sov_main)
    add_executable(sov_gguf_zero_crt_link_smoke tests/gguf_zero_crt_link_smoke.c)
    target_link_libraries(sov_gguf_zero_crt_link_smoke PRIVATE sov_rtx kernel32)
    target_compile_options(sov_gguf_zero_crt_link_smoke PRIVATE
        -ffreestanding -fno-builtin -fno-stack-protector)
    target_link_options(sov_gguf_zero_crt_link_smoke PRIVATE
        -nostdlib -Wl,--entry=sov_main)
endif()

if(SOV_BUILD_CUDA)
    find_program(PTXAS_EXECUTABLE NAMES ptxas)
    if(PTXAS_EXECUTABLE)
        set(flash_cubin "${SOV_GENERATED_DIR}/flash_attention.cubin")
        set(gemm_cubin  "${SOV_GENERATED_DIR}/gemm.cubin")
        add_custom_command(OUTPUT "${flash_cubin}"
            COMMAND "${PTXAS_EXECUTABLE}" -arch=sm_89
                    "${SOV_PTX_DIR}/flash_attention.ptx" -o "${flash_cubin}"
            DEPENDS "${SOV_PTX_DIR}/flash_attention.ptx"
            VERBATIM COMMENT "Validating flash_attention.ptx for sm_89")
        add_custom_command(OUTPUT "${gemm_cubin}"
            COMMAND "${PTXAS_EXECUTABLE}" -arch=sm_89
                    "${SOV_PTX_DIR}/gemm.ptx" -o "${gemm_cubin}"
            DEPENDS "${SOV_PTX_DIR}/gemm.ptx"
            VERBATIM COMMENT "Validating gemm.ptx for sm_89")
        add_custom_target(validate_ptx DEPENDS "${flash_cubin}" "${gemm_cubin}")
    else()
        add_custom_target(validate_ptx
            COMMAND "${CMAKE_COMMAND}" -E echo
                    "ptxas not found; cuModuleLoadData will validate PTX at runtime"
            VERBATIM)
    endif()
endif()

include(CTest)
if(BUILD_TESTING)
    add_executable(sov_rtx_host_tests
        tests/test_kv_sampler_host.c
        src/kv_allocator.c
        src/sampler.c)
    target_include_directories(sov_rtx_host_tests BEFORE PRIVATE tests/host_include)
    target_include_directories(sov_rtx_host_tests PRIVATE include src)
    add_test(NAME sov_rtx_host_tests COMMAND sov_rtx_host_tests)

    add_executable(sov_gguf_host_tests
        tests/test_gguf_host.c
        src/loader/gguf.c)
    target_include_directories(sov_gguf_host_tests PRIVATE include)
    add_test(NAME sov_gguf_host_tests COMMAND sov_gguf_host_tests)

    add_executable(sov_cuda_validation_chain_host_tests
        tests/test_cuda_validation_chain_host.c
        src/cuda_validation_chain.c)
    target_include_directories(sov_cuda_validation_chain_host_tests PRIVATE include)
    add_test(NAME sov_cuda_validation_chain_host_tests
             COMMAND sov_cuda_validation_chain_host_tests)

    add_executable(sov_cuda_kernels_host_tests
        tests/test_cuda_kernels_host.c
        src/cuda_validation_chain.c
        src/cuda_kernels.c)
    target_include_directories(sov_cuda_kernels_host_tests BEFORE PRIVATE tests/host_include)
    target_include_directories(sov_cuda_kernels_host_tests PRIVATE include src)
    add_test(NAME sov_cuda_kernels_host_tests COMMAND sov_cuda_kernels_host_tests)

    if(WIN32)
        set(SOV_CUDA_SM86_SOURCE "${SOV_GENERATED_DIR}/sov_cuda_sm86.c")
        sov_ptx_to_c_source("${SOV_PTX_DIR}/flash_attention.ptx"
                            flash_attention_ptx flash_sm86 sm_86)
        sov_ptx_to_c_source("${SOV_PTX_DIR}/gemm.ptx"
                            gemm_ptx gemm_sm86 sm_86)
        file(WRITE "${SOV_CUDA_SM86_SOURCE}"
            "/* Generated test-only sm_86 PTX blobs. */\n"
            "${flash_sm86}\n" "${gemm_sm86}\n")
        add_executable(sov_cuda_reference_gpu_test
            tests/test_cuda_reference_gpu.c
            src/kv_allocator.c
            src/cuda_validation_chain.c
            src/rowm_cuda_validation.c
            src/cuda_gemm_dispatch.c
            src/cuda_kernels.c
            windows_rtx/cuda_driver_loader.c
            "${SOV_CUDA_SM86_SOURCE}")
        target_include_directories(sov_cuda_reference_gpu_test PRIVATE include src)
        target_compile_definitions(sov_cuda_reference_gpu_test
                                   PRIVATE SOV_CUDA_COMPILED_PTX_TARGET=86)
        if(NOT MSVC)
            target_link_libraries(sov_cuda_reference_gpu_test PRIVATE m)
        endif()
        add_test(NAME sov_cuda_reference_gpu_test
                 COMMAND sov_cuda_reference_gpu_test)
        set_tests_properties(sov_cuda_reference_gpu_test
                             PROPERTIES LABELS gpu SKIP_RETURN_CODE 77)
    endif()
endif()

add_custom_target(cmm_info
    COMMAND "${CMAKE_COMMAND}" -E echo
            "C-- scheduler: src/c--/scheduler.cmm (GHC C-- backend)"
    VERBATIM)