Skip to content
44 changes: 44 additions & 0 deletions transformer_engine/common/util/cuda_runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cublasLt.h>

#include <filesystem>
#include <fstream>
#include <mutex>

#include "../common.h"
Expand Down Expand Up @@ -202,6 +203,49 @@ const std::string &include_directory(bool required) {
return path;
}

int include_directory_version(bool required) {
// Header path
const auto &include_dir = cuda::include_directory(false);
if (include_dir.empty()) {
if (required) {
NVTE_ERROR(
"Could not detect version of CUDA Toolkit headers "
"(CUDA Toolkit headers not found).");
}
return -1;
}

// Parse CUDART_VERSION from cuda_runtime_api.h.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like how we parse the header as a text file. However, when I tried compiling a test program with NVRTC it would override the header's CUDART_VERSION macro with the CUDA Runtime version.

const auto header_path = std::filesystem::path(include_dir) / "cuda_runtime_api.h";
std::ifstream header_file(header_path);
if (header_file.is_open()) {
const std::string define_prefix = "#define CUDART_VERSION ";
std::string line;
while (std::getline(header_file, line)) {
const auto pos = line.find(define_prefix);
if (pos == std::string::npos) {
continue;
}
try {
const int version = std::stoi(line.substr(pos + define_prefix.size()));
if (version > 0) {
return version;
}
} catch (...) {
continue;
}
}
}

if (required) {
NVTE_ERROR(
"Could not detect version of CUDA Toolkit headers "
"(Could not parse CUDART_VERSION from ",
header_path.string(), ").");
}
return -1;
}
Comment thread
timmoon10 marked this conversation as resolved.

int cudart_version() {
auto get_version = []() -> int {
int version;
Expand Down
15 changes: 15 additions & 0 deletions transformer_engine/common/util/cuda_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ bool supports_multicast(int device_id = -1);
*/
const std::string &include_directory(bool required = false);

/* \brief Version number of CUDA Toolkit headers
*
* The headers are accessed at run-time and its CUDA version may
* differ from compile-time and from the CUDA Runtime. The header path
* can be configured by setting NVTE_CUDA_INCLUDE_DIR in the
* environment (default is to search in common install paths).
*
* \param[in] required Whether to throw exception if headers are not
* found or if version cannot be determined.
*
* \return CUDA version encoded as major * 1000 + minor * 10, or -1 if
* it could not be determined.
*/
int include_directory_version(bool required = false);

/* \brief CUDA Runtime version number at run-time
*
* Versions may differ between compile-time and run-time.
Expand Down
37 changes: 35 additions & 2 deletions transformer_engine/common/util/rtc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "../common.h"
#include "../util/cuda_driver.h"
#include "../util/cuda_runtime.h"
#include "../util/string.h"
#include "../util/system.h"

Expand Down Expand Up @@ -175,14 +176,46 @@ void KernelManager::compile(const std::string& kernel_label, const std::string&
const nvrtcResult compile_result =
nvrtcCompileProgram(program, opts_ptrs.size(), opts_ptrs.data());
if (compile_result != NVRTC_SUCCESS) {
// Display log if compilation failed
std::string log = concat_strings("NVRTC compilation log for ", filename, ":\n");
std::string log;

// Decode CUDA version number to "major.minor" string
auto version_string = [](int v) -> std::string {
if (v < 0) {
return "<not found>";
}
return concat_strings(v / 1000, ".", (v % 1000) / 10);
};

// Check CUDA versions
const int build_version = CUDA_VERSION;
int nvrtc_version = -1;
int nvrtc_version_major = 0, nvrtc_version_minor = 0;
if (nvrtcVersion(&nvrtc_version_major, &nvrtc_version_minor) == NVRTC_SUCCESS) {
nvrtc_version = nvrtc_version_major * 1000 + nvrtc_version_minor * 10;
}
const int header_version = cuda::include_directory_version();
log += concat_strings("Compile-time CUDA version: ", version_string(build_version), "\n",
"Run-time NVRTC version: ", version_string(nvrtc_version), "\n",
"Run-time CUDA headers version: ", version_string(header_version), "\n");
if (nvrtc_version != header_version) {
log += concat_strings(
"\nWarning: CUDA versions do not match between NVRTC and CUDA headers (",
cuda::include_directory(),
"). "
"Consider changing the CUDA header search path (by setting NVTE_CUDA_INCLUDE_DIR) "
"or the linked CUDA Runtime (by setting CUDA_HOME or LD_LIBRARY_PATH).\n\n");
}
Comment thread
timmoon10 marked this conversation as resolved.

// Get build log
log += concat_strings("NVRTC compilation log for ", filename, ":\n");
const size_t log_offset = log.size();
size_t log_size;
NVTE_CHECK_NVRTC(nvrtcGetProgramLogSize(program, &log_size));
log.resize(log_offset + log_size);
NVTE_CHECK_NVRTC(nvrtcGetProgramLog(program, &log[log_offset]));
log.back() = '\n';

// Display log and throw error
std::cerr << log;
NVTE_CHECK_NVRTC(compile_result);
}
Expand Down
Loading