Repository navigation
[FEA] LTO IR Support (1) - Introduce LibRTCX #21625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 250 commits
ff2f88f
44c1344
86c0010
ae39c7c
a955a04
7d2a2bb
82ddae0
43a4e08
37976fc
17ebfa0
6fbc5a4
5aa1ea5
fab6e6e
5738218
33b93a4
c34420a
6be76aa
d83a397
8b58392
b2be86b
3ecf30d
925171d
8fd14de
c9aedc9
bae7fde
e2915e7
4480033
ba8f921
f68d4f0
dca589e
def9833
22eef22
613eb37
1d53fc8
112ae32
32383c0
21a2610
c82867b
badacea
6f829ac
ec95217
5e0f2e7
93b57a5
5ffddda
4414b4e
dbaa133
7e5fb74
ca50cc9
db2e2dd
75916e4
8bb341d
4bb406a
e53bf52
bdc6597
6c9be74
8dba8b8
e8250e2
e55ba0f
aa2fd4d
f708ff9
69ff5e1
2ab3bc5
176d356
8efd349
8ff447d
4bd0c72
cfc1e23
c82923c
b279d49
21a8733
40f4129
ddd251d
2e1bbab
10c6410
ce31d17
ddfbba1
ac12ff7
5ea3317
3bd4106
78bdf40
9fe78f3
2854850
68e7974
f7f55a8
084f735
71e25ce
cdb66c6
b64eb2e
b9a2153
43b1dbf
16386fd
ea11f0b
422ea0a
96d254c
a0ee09d
11e01b3
6bc9c0b
9be6531
40d46cf
df6bd8d
060d369
4ba506a
c21c228
476025e
7e8c903
3aa3b20
e1a6f43
b382e49
a8f8c3d
3f92780
49d81e6
70c558c
c0b947b
742b88a
d27a094
6b4fe05
cc503e2
24c450a
29cfcc7
22b189b
c9e651c
4932483
eb1b4f2
c43ac2f
c261b83
3bc9868
25a35f0
cedd9bd
45e48f5
6a1267f
8f50bb3
6cf08ca
f2282ac
7bfd0a8
ed68841
dd64fd9
b6db8f2
485107e
85e96db
f6209b1
bbe8d5c
c46450e
8c30430
f8fcc70
4ba9950
74286e0
25901ea
2b5dbc5
a521f47
3b70eb3
843dbd5
d44bbbb
5101289
58a6385
49f94ed
70f62f1
7616d54
bdbed4b
689495f
ea2ef02
18372f7
0112b98
9cc8747
222618d
1c0def6
b37b545
ed81710
95925f9
225e597
8085323
f0646bc
6af15c0
ea82e0d
4c7e43d
3c5adc7
d42466d
1e5cb73
0ec6804
0dbb87b
28295bb
aa3f3c3
6682abd
d9f4185
0055ca0
8a9878c
c59d13f
43f9cd0
b7c9f3c
d0e86fd
067123e
57d1192
36d06ae
fae6e2c
2301055
bfa6782
32eb792
9ae5096
95591ba
610beab
457ee40
855b246
2c98a35
37d6696
49636cc
169618d
b5cd518
3c607ca
1c025b4
8c3ac2f
4a17020
2c497dc
72a17bc
29826d4
f3f72b2
9ed9325
8c7f368
6fe3108
2e647ef
e9ec212
6f5a542
01b42c2
5188eca
0b0ba2f
0ea5656
6b2e0e7
dc95bba
40fd3eb
12b8cf7
6e3840e
630beab
3f5fc79
8aad236
eb3ef79
1bbc0f8
03ec682
00b32b3
8bde405
463d008
2a26428
df6c97d
2662703
ac0caaa
908cf50
48d1ec0
cbfc086
56ac249
a138cb7
a0ec040
59593ed
d146ece
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Doc | ||
|
|
||
| RTCX (runtime-compiler extended) is a wrapper around NVRTC and NVJitLink designed to provide: | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
|
|
||
| - User-controlled compilation, linking, caching, and pre-loading of CUDA kernels | ||
| - Zero-copy interfaces to manage JIT compilation and linking | ||
| - CMake script to embed **compressed** headers directly into an executable without incurring overhead at runtime on every compilation request | ||
| - Facilities to pre-load and teardown dynamic library dependencies (`libcuda`, `libnvrtc`, and `libnvJitlink`) | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
|
|
||
| ## Platforms Supported | ||
| - Linux | ||
|
|
||
| ## Build-Scripting Requirements | ||
| - CMake | ||
| - LibZSTD - for binary compression | ||
|
|
||
| ## Runtime Requirements | ||
| - CUDA >= 11.8 | ||
|
lamarrr marked this conversation as resolved.
Resolved
lamarrr marked this conversation as resolved.
Resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,301 @@ | ||
| # ============================================================================= | ||
| # cmake-format: off | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # cmake-format: on | ||
| # ============================================================================= | ||
|
|
||
| if(NOT TARGET zstd) | ||
| message( | ||
| FATAL_ERROR "zstd library is required for JIT embedding. Please ensure it is found by CMake." | ||
| ) | ||
| endif() | ||
|
|
||
| # This function initializes a target for JIT embedding. It must be called before any calls to | ||
| # embed_includes() or embed_blob() for the target. It sets up necessary variables and state to track | ||
| # the registered files and dependencies for the target. The TARGET argument specifies the name of | ||
| # the target being initialized. | ||
| function(add_embed) | ||
| set(TARGET ${ARGV0}) | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| set(OPTIONS "") | ||
| set(ONE_VALUE_ARGS) | ||
| set(MULTI_VALUE_ARGS) | ||
| cmake_parse_arguments(ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) | ||
|
|
||
| if(NOT DEFINED TARGET) | ||
| message(FATAL_ERROR "TARGET argument is required") | ||
| endif() | ||
|
|
||
| set(${TARGET}_FILE_INDEX | ||
| 0 | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}_INITIALIZED | ||
| TRUE | ||
| PARENT_SCOPE | ||
| ) | ||
| endfunction() | ||
|
|
||
| # This function registers a directory of include files to be embedded for JIT compilation. | ||
| function(embed_includes) | ||
| set(TARGET ${ARGV0}) | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| set(OPTIONS "") | ||
| set(ONE_VALUE_ARGS COPY_DIRECTORY # Source directory where files will be copied from | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| DEST_DIRECTORY # Destination directory where files will be copied to | ||
| ) | ||
| set(MULTI_VALUE_ARGS | ||
| FILES # Source files relative to COPY_DIRECTORY (optional, if not provided, all files under | ||
| # COPY_DIRECTORY will be used) | ||
| INCLUDE_DIRECTORIES # Include directories to be used when compiling with these files | ||
| ) | ||
| cmake_parse_arguments(ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) | ||
|
|
||
| if(NOT DEFINED TARGET OR NOT ${TARGET}_INITIALIZED) | ||
| message(FATAL_ERROR "embed target '${TARGET}' has not been initialized with add_embed()") | ||
| endif() | ||
|
|
||
| if(NOT ARG_COPY_DIRECTORY | ||
| OR NOT ARG_DEST_DIRECTORY | ||
| OR NOT ARG_INCLUDE_DIRECTORIES | ||
| ) | ||
| message( | ||
| FATAL_ERROR "COPY_DIRECTORY, DEST_DIRECTORY, and INCLUDE_DIRECTORIES arguments are required" | ||
| ) | ||
| endif() | ||
|
|
||
| if(NOT ARG_FILES) | ||
| # gather all include files under the specified directory | ||
| file(GLOB_RECURSE INCLUDE_FILES "${ARG_COPY_DIRECTORY}/*") | ||
|
|
||
| # get their paths relative to the base include directory | ||
| set(INCLUDE_FILES_RELATIVE_PATHS "") | ||
| foreach(INCLUDE_FILE IN LISTS INCLUDE_FILES) | ||
| file(RELATIVE_PATH INCLUDE_FILE_REL_PATH "${ARG_COPY_DIRECTORY}" "${INCLUDE_FILE}") | ||
| list(APPEND INCLUDE_FILES_RELATIVE_PATHS "${INCLUDE_FILE_REL_PATH}") | ||
| endforeach() | ||
|
|
||
| set(ARG_FILES ${INCLUDE_FILES_RELATIVE_PATHS}) | ||
| endif() | ||
|
|
||
| # check that each source file exists | ||
| foreach(SOURCE_FILE IN LISTS ARG_FILES) | ||
| if(NOT EXISTS "${ARG_COPY_DIRECTORY}/${SOURCE_FILE}") | ||
| message(FATAL_ERROR "Source file '${ARG_COPY_DIRECTORY}/${SOURCE_FILE}' does not exist") | ||
| endif() | ||
| endforeach(SOURCE_FILE) | ||
|
|
||
| # Set scope variables to accumulate results | ||
|
|
||
| set(SOURCE_FILE_IDS ${${TARGET}__embed__source_file_ids}) | ||
| set(SOURCE_FILES ${${TARGET}__embed__source_files}) | ||
| set(SOURCE_FILE_DESTS ${${TARGET}__embed__source_file_dests}) | ||
| set(INCLUDE_DIRECTORIES ${${TARGET}__embed__include_directories}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This approach is fine, but potentially a bit error-prone because you're subject to scoping rules on each of the variables. It would be a bit cleaner to use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we do this as refactoring for later?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, later is fine. |
||
|
|
||
| foreach(SOURCE_FILE IN LISTS ARG_FILES) | ||
| list(LENGTH SOURCE_FILE_IDS SOURCE_FILE_IDS_LENGTH) | ||
|
vyasr marked this conversation as resolved.
Resolved
|
||
| list(APPEND SOURCE_FILE_IDS "include_${SOURCE_FILE_IDS_LENGTH}") | ||
| list(APPEND SOURCE_FILES "${ARG_COPY_DIRECTORY}/${SOURCE_FILE}") | ||
| list(APPEND SOURCE_FILE_DESTS "${ARG_DEST_DIRECTORY}/${SOURCE_FILE}") | ||
| endforeach() | ||
|
|
||
| list(APPEND INCLUDE_DIRECTORIES ${ARG_INCLUDE_DIRECTORIES}) | ||
|
|
||
| list(LENGTH SOURCE_FILE_IDS SOURCE_FILE_IDS_LENGTH) | ||
|
|
||
| set(${TARGET}_FILE_INDEX | ||
| ${SOURCE_FILE_IDS_LENGTH} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__source_file_ids | ||
| ${SOURCE_FILE_IDS} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__source_files | ||
| ${SOURCE_FILES} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__source_file_dests | ||
| ${SOURCE_FILE_DESTS} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__include_directories | ||
| ${INCLUDE_DIRECTORIES} | ||
| PARENT_SCOPE | ||
| ) | ||
|
|
||
| endfunction() | ||
|
|
||
| # This function registers a single file to be embedded for JIT compilation. | ||
| function(embed_blob) | ||
| set(TARGET ${ARGV0}) | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| set(OPTIONS) | ||
| set(ONE_VALUE_ARGS ID FILE DEST) | ||
| set(MULTI_VALUE_ARGS ARRAY_IDS ARRAY_VALUES) | ||
| cmake_parse_arguments(ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) | ||
|
|
||
| if(NOT DEFINED TARGET OR NOT ${TARGET}_INITIALIZED) | ||
| message(FATAL_ERROR "embed target '${TARGET}' has not been initialized with add_embed()") | ||
| endif() | ||
|
|
||
| if(NOT ARG_ID | ||
| OR NOT ARG_FILE | ||
| OR NOT ARG_DEST | ||
| ) | ||
| message(FATAL_ERROR "ID, FILE, and DEST arguments are required") | ||
| endif() | ||
|
|
||
| set(SOURCE_FILE_IDS ${${TARGET}__embed__source_file_ids}) | ||
| set(SOURCE_FILES ${${TARGET}__embed__source_files}) | ||
| set(SOURCE_FILE_DESTS ${${TARGET}__embed__source_file_dests}) | ||
| set(TARGET_DEPS ${${TARGET}__embed__target_deps}) | ||
| set(ARRAY_IDS ${${TARGET}__embed__array_ids}) | ||
| set(ARRAY_VALUES ${${TARGET}__embed__array_values}) | ||
|
|
||
| if(ARG_ARRAY_IDS) | ||
| if(NOT ARG_ARRAY_VALUES) | ||
| message(FATAL_ERROR "ARRAY_VALUES argument is required when ARRAY_IDS is provided") | ||
| endif() | ||
|
|
||
| list(LENGTH ARG_ARRAY_IDS ARG_ARRAY_IDS_LENGTH) | ||
| list(LENGTH ARG_ARRAY_VALUES ARG_ARRAY_VALUES_LENGTH) | ||
|
|
||
| if(NOT ARG_ARRAY_IDS_LENGTH EQUAL ARG_ARRAY_VALUES_LENGTH) | ||
| message(FATAL_ERROR "ARRAY_IDS and ARRAY_VALUES must have the same length") | ||
| endif() | ||
|
|
||
| list(APPEND ARRAY_IDS ${ARG_ARRAY_IDS}) | ||
| list(APPEND ARRAY_VALUES ${ARG_ARRAY_VALUES}) | ||
| endif() | ||
|
|
||
| if(ARG_FILE MATCHES "\\$<TARGET_OBJECTS:([^>]+)>") | ||
| # If the file is a generator expression for target objects add as dependency | ||
| list(APPEND TARGET_DEPS $<TARGET_OBJECTS:${CMAKE_MATCH_1}>) | ||
| else() | ||
| if(NOT EXISTS "${ARG_FILE}") | ||
| message(FATAL_ERROR "Source file '${ARG_FILE}' does not exist") | ||
| endif() | ||
| endif() | ||
| list(APPEND SOURCE_FILE_IDS ${ARG_ID}) | ||
| list(APPEND SOURCE_FILES ${ARG_FILE}) | ||
| list(APPEND SOURCE_FILE_DESTS ${ARG_DEST}) | ||
|
|
||
| list(LENGTH SOURCE_FILE_IDS SOURCE_FILE_IDS_LENGTH) | ||
|
|
||
| set(${TARGET}_FILE_INDEX | ||
| ${SOURCE_FILE_IDS_LENGTH} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__source_file_ids | ||
| ${SOURCE_FILE_IDS} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__source_files | ||
| ${SOURCE_FILES} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__source_file_dests | ||
| ${SOURCE_FILE_DESTS} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__target_deps | ||
| ${TARGET_DEPS} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__array_ids | ||
| ${ARRAY_IDS} | ||
| PARENT_SCOPE | ||
| ) | ||
| set(${TARGET}__embed__array_values | ||
| ${ARRAY_VALUES} | ||
| PARENT_SCOPE | ||
| ) | ||
|
|
||
| endfunction() | ||
|
|
||
| # This function generates the necessary files and build targets to embed the registered source files | ||
| # for JIT compilation. | ||
| function(embed) | ||
| set(TARGET ${ARGV0}) | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| set(OPTIONS "") | ||
| set(ONE_VALUE_ARGS "COMPRESSION") | ||
| set(MULTI_VALUE_ARGS "") | ||
| cmake_parse_arguments(ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) | ||
|
|
||
| if(NOT DEFINED TARGET OR NOT ${TARGET}_INITIALIZED) | ||
| message(FATAL_ERROR "embed target '${TARGET}' has not been initialized with add_embed()") | ||
| endif() | ||
|
|
||
| if(NOT DEFINED ARG_COMPRESSION) | ||
| message(FATAL_ERROR "COMPRESSION argument is required") | ||
| endif() | ||
|
|
||
| if(NOT ARG_COMPRESSION STREQUAL "none" AND NOT ARG_COMPRESSION STREQUAL "zstd") | ||
| message(FATAL_ERROR "COMPRESSION argument must be either none or zstd") | ||
| endif() | ||
|
|
||
| if(NOT DEFINED ${TARGET}__embed__source_files) | ||
| message(FATAL_ERROR "No source files registered for target '${TARGET}'") | ||
| endif() | ||
|
|
||
| set(OUTPUT_DIR "${CUDF_GENERATED_INCLUDE_DIR}/rtcx_embed") | ||
| set(EMBED_SCRIPT_TEMPLATE "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/embed.in.cpp") | ||
| set(CONFIGURED_EMBED_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}__embed_cfg.cpp") | ||
| set(EMBED_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}__embed.cpp") | ||
|
|
||
| set(EMBED_SCRIPT__ID "${TARGET}") | ||
| set(EMBED_SCRIPT__ARRAY_IDS "${${TARGET}__embed__array_ids}") | ||
| set(EMBED_SCRIPT__ARRAY_VALUES "${${TARGET}__embed__array_values}") | ||
| set(EMBED_SCRIPT__FILE_IDS "${${TARGET}__embed__source_file_ids}") | ||
| set(EMBED_SCRIPT__FILE_PATHS "${${TARGET}__embed__source_files}") | ||
| set(EMBED_SCRIPT__FILE_DESTS "${${TARGET}__embed__source_file_dests}") | ||
| set(EMBED_SCRIPT__INCLUDE_DIRS "${${TARGET}__embed__include_directories}") | ||
| set(EMBED_SCRIPT__COMPRESSION "${ARG_COMPRESSION}") | ||
| set(EMBED_SCRIPT__OUTPUT_DIR "${OUTPUT_DIR}") | ||
|
|
||
| configure_file(${EMBED_SCRIPT_TEMPLATE} ${CONFIGURED_EMBED_SCRIPT} @ONLY) | ||
| file( | ||
| GENERATE | ||
| OUTPUT "${EMBED_SCRIPT}" | ||
| INPUT "${CONFIGURED_EMBED_SCRIPT}" | ||
| ) | ||
|
|
||
| add_executable("${TARGET}__jit_embed_run" EXCLUDE_FROM_ALL "${EMBED_SCRIPT}") | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| target_include_directories("${TARGET}__jit_embed_run" PRIVATE ${ZSTD_INCLUDE_DIR}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this necessary? Does the zstd target below not bring in the right include directories itself?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it uses the zstd.a library and the include has to be specified separately just as in: https://github.com/lamarrr/cudf/blob/03ec682aa3065fb26b82c287289256ca4d59bb6a/cpp/CMakeLists.txt#L1029
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm OK we can investigate more in a follow-up. |
||
| target_link_libraries("${TARGET}__jit_embed_run" PRIVATE ${CMAKE_DL_LIBS} zstd) | ||
| set_target_properties( | ||
| "${TARGET}__jit_embed_run" PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES | ||
| ) | ||
| target_include_directories("${TARGET}__jit_embed_run" PRIVATE ${CMAKE_CURRENT_FUNCTION_LIST_DIR}) | ||
|
|
||
| add_custom_command( | ||
| OUTPUT ${OUTPUT_DIR}/${TARGET}.hpp ${OUTPUT_DIR}/${TARGET}.s ${OUTPUT_DIR}/${TARGET}.bin | ||
| COMMAND "${CMAKE_COMMAND}" -E env $<TARGET_FILE:${TARGET}__jit_embed_run> | ||
| DEPENDS "${CONFIGURED_EMBED_SCRIPT}" "${EMBED_SCRIPT}" ${${TARGET}__embed__source_files} | ||
|
lamarrr marked this conversation as resolved.
Resolved
|
||
| ${${TARGET}__embed__target_deps} | ||
| WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" | ||
| COMMENT "Generating JIT embed for ${TARGET} into ${OUTPUT_DIR}" | ||
| VERBATIM | ||
| ) | ||
|
|
||
| add_custom_target( | ||
| ${TARGET} ALL | ||
| DEPENDS ${OUTPUT_DIR}/${TARGET}.hpp ${OUTPUT_DIR}/${TARGET}.s ${OUTPUT_DIR}/${TARGET}.bin | ||
| COMMENT "Custom target for JIT embed of ${TARGET}" | ||
| ) | ||
|
|
||
| message( | ||
| STATUS | ||
| "JIT embed for target ${TARGET} will be generated into: ${OUTPUT_DIR}/${TARGET}.hpp ${OUTPUT_DIR}/${TARGET}.s ${OUTPUT_DIR}/${TARGET}.bin" | ||
| ) | ||
|
|
||
| set(${TARGET}_INCLUDE_DIRS | ||
| "${OUTPUT_DIR}" | ||
| PARENT_SCOPE | ||
| ) | ||
|
|
||
| set(${TARGET}_SOURCE_DIR | ||
| ${OUTPUT_DIR} | ||
| PARENT_SCOPE | ||
| ) | ||
|
|
||
| endfunction() | ||
Uh oh!
There was an error while loading. Please reload this page.