Skip to content

Commit b7e5178

Browse files
committed
feat: Trilu and Logic operator implementations, several GPU optimizations
1 parent 2a98dca commit b7e5178

130 files changed

Lines changed: 3767 additions & 501 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.

benchmark/CMakeLists.txt

Lines changed: 112 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,36 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
3636
file(GLOB BENCHMARK_ONNX_MODELS
3737
"${CMAKE_CURRENT_SOURCE_DIR}/models/*.onnx")
3838

39+
# Exclude the base/template models used by specialize_models.py to generate
40+
# fixed-size variants (e.g. gnn_h32_k2_n100_e500.onnx). The base models
41+
# have symbolic dim_param input dimensions that SOFIE cannot resolve during
42+
# code generation:
43+
# • GetTensorShape() throws "unspecified dimension parameter" for input
44+
# tensors whose shapes were not concretised by ONNX shape inference.
45+
# • GetTensorShape() throws "is a dynamic tensor" when an operator tries
46+
# to read a concrete size from an intermediate tensor that remained
47+
# dynamic because its input shapes were unknown.
48+
# The concrete specialised variants produced by specialize_models.py are
49+
# benchmarked instead.
50+
list(FILTER BENCHMARK_ONNX_MODELS EXCLUDE REGEX
51+
"/(gnn_h32_k2|gnn_h64_k4|punet_h32_k2_heads4_layers2|punet_h64_k4_heads4_layers2|transformer_d32_h2_L6_ff32)\\.onnx$")
52+
53+
# Exclude models that exceed GPU memory (cudaErrorMemoryAllocation) or trigger
54+
# a cuBLAS EXECUTION_FAILED error (status 13) on the available hardware
55+
# (RTX 2070 SUPER, 8 GB VRAM). They stay on disk for reference but are not
56+
# included in the benchmark binary.
57+
list(FILTER BENCHMARK_ONNX_MODELS EXCLUDE REGEX
58+
"/(punet_h32_k2_heads4_layers2_n10000_e50000\
59+
|punet_h32_k2_heads4_layers2_n1000_e5000\
60+
|punet_h32_k2_heads4_layers2_n3000_e15000\
61+
|punet_h64_k4_heads4_layers2_n10000_e50000\
62+
|punet_h64_k4_heads4_layers2_n100_e500\
63+
|punet_h64_k4_heads4_layers2_n300_e1500\
64+
|punet_h64_k4_heads4_layers2_n3000_e15000\
65+
|transformer_L1000_B100\
66+
|transformer_L100_B100\
67+
|transformer_L8000_B1)\\.onnx$")
68+
3969
if(NOT BENCHMARK_ONNX_MODELS)
4070
message(STATUS
4171
"SOFIE Benchmark: No .onnx models found in benchmark/models/. "
@@ -142,21 +172,13 @@ set(_EMIT_BLOCK
142172
}\n\
143173
")
144174

145-
set(_RUN_BLOCK
146-
" Benchmark_@3@(warmup, iterations, weightsDir);\n\
147-
")
148-
149-
# ORT call: passes the full ONNX path directly (no SOFIE weights needed)
150-
set(_ORT_RUN_BLOCK
151-
"#ifdef SOFIE_BENCHMARK_ORT\n\
152-
if (run_ort) BenchmarkORT_GPU(\"@1@\", \"@2@\", warmup, iterations);\n\
153-
#endif\n\
154-
")
155-
156-
set(BENCHMARK_EMIT_CAPTURES "")
157-
set(BENCHMARK_BENCH_HEADERS "")
158-
set(BENCHMARK_RUN_CALLS "")
159-
set(GENERATED_HEADERS "")
175+
set(BENCHMARK_EMIT_CAPTURES "")
176+
set(BENCHMARK_BENCH_HEADERS "")
177+
set(BENCHMARK_FWD_DECLS "")
178+
set(BENCHMARK_SINGLE_MODEL_CASES "")
179+
set(BENCHMARK_SPAWN_CALLS "")
180+
set(GENERATED_HEADERS "")
181+
set(BENCHMARK_MODEL_CU_SRCS "")
160182

161183
foreach(ONNX_FILE ${BENCHMARK_ONNX_MODELS})
162184
get_filename_component(MODEL_NAME "${ONNX_FILE}" NAME_WE)
@@ -167,21 +189,52 @@ foreach(ONNX_FILE ${BENCHMARK_ONNX_MODELS})
167189
set(GEN_BENCH "${CMAKE_CURRENT_BINARY_DIR}/${MODEL_NAME}_bench.hxx")
168190
list(APPEND GENERATED_HEADERS "${GEN_HXX}" "${GEN_BENCH}")
169191

170-
string(REPLACE "@1@" "${ONNX_FILE}" _emit_cap "${_EMIT_BLOCK}")
171-
string(REPLACE "@2@" "${MODEL_NAME}" _emit_cap "${_emit_cap}")
192+
string(REPLACE "@1@" "${ONNX_FILE}" _emit_cap "${_EMIT_BLOCK}")
193+
string(REPLACE "@2@" "${MODEL_NAME}" _emit_cap "${_emit_cap}")
172194
string(APPEND BENCHMARK_EMIT_CAPTURES "${_emit_cap}")
173195

174-
# SOFIE Alpaka call
175-
string(REPLACE "@3@" "${MODEL_CPPNAME}" _run_cap "${_RUN_BLOCK}")
176-
string(APPEND BENCHMARK_RUN_CALLS "${_run_cap}")
177-
178-
# ORT call (guarded by #ifdef at compile time + run_ort flag at runtime)
179-
string(REPLACE "@1@" "${ONNX_FILE}" _ort_cap "${_ORT_RUN_BLOCK}")
180-
string(REPLACE "@2@" "${MODEL_NAME}" _ort_cap "${_ort_cap}")
181-
string(APPEND BENCHMARK_RUN_CALLS "${_ort_cap}")
182-
183196
string(APPEND BENCHMARK_BENCH_HEADERS
184197
"#include \"${MODEL_NAME}_bench.hxx\"\n")
198+
199+
# Forward declaration for the main TU (function defined in per-model .cu)
200+
string(APPEND BENCHMARK_FWD_DECLS
201+
"void Benchmark_${MODEL_CPPNAME}(int warmup, int iterations, const std::string& weightsDir);\n")
202+
203+
# Single-model dispatch: one if-branch per model (used in --single-model mode)
204+
string(APPEND BENCHMARK_SINGLE_MODEL_CASES
205+
" if (model == \"${MODEL_CPPNAME}\") {\n"
206+
" Benchmark_${MODEL_CPPNAME}(warmup, iterations, weightsDir);\n"
207+
"#ifdef SOFIE_BENCHMARK_ORT\n"
208+
" if (run_ort) BenchmarkORT_GPU(\"${ONNX_FILE}\", \"${MODEL_NAME}\", warmup, iterations);\n"
209+
"#endif\n"
210+
" return 0;\n"
211+
" }\n"
212+
)
213+
214+
# Subprocess spawn: run this binary as a child with --single-model <name>.
215+
# Each child gets a fresh CUDA context so GPU memory from the previous
216+
# model is completely freed before the next one allocates.
217+
string(APPEND BENCHMARK_SPAWN_CALLS
218+
" {\n"
219+
" std::string cmd = std::string(argv[0])\n"
220+
" + \" --single-model ${MODEL_CPPNAME}\"\n"
221+
" + commonArgs;\n"
222+
" int rc = std::system(cmd.c_str());\n"
223+
" if (rc != 0) {\n"
224+
" std::fprintf(stderr, \"[ERROR] ${MODEL_NAME}: subprocess exited %d\\n\", rc);\n"
225+
" ++totalFailed;\n"
226+
" }\n"
227+
" }\n"
228+
)
229+
230+
# Per-model compilation unit: include one bench.hxx → one .cu file
231+
set(_model_cu "${CMAKE_CURRENT_BINARY_DIR}/${MODEL_NAME}_bench.cu")
232+
configure_file(
233+
"${CMAKE_CURRENT_SOURCE_DIR}/src/ModelBench.cu.in"
234+
"${_model_cu}"
235+
@ONLY
236+
)
237+
list(APPEND BENCHMARK_MODEL_CU_SRCS "${_model_cu}")
185238
endforeach()
186239

187240
################################################################################
@@ -194,7 +247,9 @@ configure_file(
194247
@ONLY
195248
)
196249

197-
set(RUNNER_SRC "${CMAKE_CURRENT_BINARY_DIR}/BenchmarkRunner_all.cu")
250+
# Main runner: only main() + forward declarations (no model headers).
251+
# Each model is compiled in its own _bench.cu TU (see BENCHMARK_MODEL_CU_SRCS).
252+
set(RUNNER_SRC "${CMAKE_CURRENT_BINARY_DIR}/BenchmarkRunner_main.cpp")
198253
configure_file(
199254
"${CMAKE_CURRENT_SOURCE_DIR}/src/BenchmarkRunner.cxx.in"
200255
"${RUNNER_SRC}"
@@ -247,9 +302,13 @@ add_custom_target(sofie_benchmark_headers
247302
# Benchmark runner (compiled as .cu, same as the test suite)
248303
################################################################################
249304

250-
set_source_files_properties("${RUNNER_SRC}" PROPERTIES LANGUAGE CUDA)
305+
# Mark every per-model bench.cu as CUDA so nvcc processes the device kernels.
306+
set_source_files_properties(${BENCHMARK_MODEL_CU_SRCS} PROPERTIES LANGUAGE CUDA)
251307

252-
add_executable(sofie_benchmark "${RUNNER_SRC}")
308+
# The main runner is plain C++ (no CUDA kernels, just calls forward-declared fns).
309+
set_source_files_properties("${RUNNER_SRC}" PROPERTIES LANGUAGE CXX)
310+
311+
add_executable(sofie_benchmark "${RUNNER_SRC}" ${BENCHMARK_MODEL_CU_SRCS})
253312

254313
add_dependencies(sofie_benchmark sofie_benchmark_headers)
255314

@@ -261,9 +320,22 @@ target_include_directories(sofie_benchmark PRIVATE
261320
"${CUDAToolkit_INCLUDE_DIRS}"
262321
)
263322

323+
# Default to the native GPU architecture so we compile only one arch (saves
324+
# memory and time). The previous "70;75;80;86;89;90" multi-arch list caused
325+
# nvcc to OOM-kill when processing all models. Override via
326+
# cmake -DSOFIE_BENCHMARK_CUDA_ARCH="75;86" .
327+
if(NOT DEFINED SOFIE_BENCHMARK_CUDA_ARCH OR SOFIE_BENCHMARK_CUDA_ARCH STREQUAL "")
328+
if(CMAKE_CUDA_ARCHITECTURES AND NOT CMAKE_CUDA_ARCHITECTURES STREQUAL "")
329+
set(SOFIE_BENCHMARK_CUDA_ARCH "${CMAKE_CUDA_ARCHITECTURES}")
330+
else()
331+
set(SOFIE_BENCHMARK_CUDA_ARCH "75") # RTX 2070 SUPER default
332+
endif()
333+
endif()
334+
message(STATUS "SOFIE Benchmark: CUDA architectures = ${SOFIE_BENCHMARK_CUDA_ARCH}")
335+
264336
set_target_properties(sofie_benchmark PROPERTIES
265337
CUDA_SEPARABLE_COMPILATION OFF
266-
CUDA_ARCHITECTURES "70;75;80;86;89;90"
338+
CUDA_ARCHITECTURES "${SOFIE_BENCHMARK_CUDA_ARCH}"
267339
CUDA_STANDARD 20
268340
CUDA_STANDARD_REQUIRED ON
269341
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
@@ -280,8 +352,17 @@ target_compile_options(sofie_benchmark PRIVATE
280352
--extended-lambda
281353
--expt-relaxed-constexpr
282354
--use_fast_math
283-
-O2
355+
-O1
284356
-Wno-deprecated-gpu-targets
357+
# Suppress "variable was declared but never referenced" (#177-D).
358+
# Generated Expand/Where kernels compute per-dimension indices for
359+
# broadcast dimensions; when a dimension has size 1 the index variable
360+
# is always 0 and goes unused. Without this suppress the CUDA device
361+
# compiler counts them against its error-budget and stops compilation.
362+
-diag-suppress 177
363+
# Limit device register usage to reduce per-kernel memory footprint
364+
# during compilation of the large all-models TU.
365+
--maxrregcount=64
285366
>
286367
$<$<COMPILE_LANGUAGE:CXX>:
287368
-O2

benchmark/models/gnn_h32_k2.onnx

120 KB
Binary file not shown.
127 KB
Binary file not shown.
127 KB
Binary file not shown.
127 KB
Binary file not shown.
127 KB
Binary file not shown.
127 KB
Binary file not shown.

benchmark/models/gnn_h64_k4.onnx

641 KB
Binary file not shown.
653 KB
Binary file not shown.
653 KB
Binary file not shown.

0 commit comments

Comments
 (0)