Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion projects/clr/rocclr/device/hotswap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace amd {
namespace hotswap {

// On when this tool is loaded via HSA_TOOLS_LIB (name must match ROCR LoadTools).
inline constexpr const char* kHotswapToolLib = "libamd_comgr_hotswap_tool.so";
inline constexpr const char* kHotswapToolLib = "libhsa-hotswap.so";

inline bool Enabled() {
const char* tools_lib = std::getenv("HSA_TOOLS_LIB");
Expand Down
25 changes: 24 additions & 1 deletion projects/hotswap/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.16)
project(hotswap LANGUAGES CXX)

include(GNUInstallDirs)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

Expand All @@ -10,6 +12,7 @@ set(HSA_RUNTIME_INC "${CMAKE_CURRENT_SOURCE_DIR}/../rocr-runtime/runtime/hsa-run

# COMGR is required — provides amd_comgr_hotswap_rewrite.
find_package(amd_comgr CONFIG REQUIRED)
find_package(hsa-runtime64 CONFIG REQUIRED)

find_path(HSA_INCLUDE_DIR hsa.h PATHS ${HSA_RUNTIME_INC} NO_DEFAULT_PATH REQUIRED)

Expand All @@ -36,15 +39,35 @@ target_include_directories(hsa-hotswap PRIVATE
${HSA_RUNTIME_INC}/..
)

target_link_libraries(hsa-hotswap PRIVATE amd_comgr)
target_link_libraries(hsa-hotswap PRIVATE
amd_comgr
hsa-runtime64::hsa-runtime64
Comment thread
nirmie marked this conversation as resolved.
)
set_target_properties(hsa-hotswap PROPERTIES
POSITION_INDEPENDENT_CODE ON)

install(TARGETS hsa-hotswap
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Test executable
add_executable(hotswap_test tests/hotswap_test.cpp hotswap.cpp)
target_include_directories(hotswap_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(hotswap_test PRIVATE amd_comgr)

# Embed the gfx1250 fixture code object as a byte array so the test exercises the
# real parse + rewrite path with no GPU and no runtime file dependency (works in
# any CI). Regenerate the .hsaco per tests/fixtures/README.md.
set(_hotswap_co "${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/gfx1250_min.hsaco")
set(_hotswap_co_hdr "${CMAKE_CURRENT_BINARY_DIR}/gfx1250_min_hsaco.h")
file(READ "${_hotswap_co}" _hotswap_co_hex HEX)
string(REGEX REPLACE "(..)" "0x\\1," _hotswap_co_arr "${_hotswap_co_hex}")
file(WRITE "${_hotswap_co_hdr}"
"// Generated from tests/fixtures/gfx1250_min.hsaco. Do not edit.\n"
"static const unsigned char kGfx1250MinCo[] = {${_hotswap_co_arr}};\n")
target_include_directories(hotswap_test PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

# Unit tests for the gfx-target / ASIC-revision query logic. The test compiles
# the portable hotswap_gfx_query.cpp unit alongside the test translation unit
# and supplies its own stubs for the HSA entry points, so this target needs
Expand Down
40 changes: 38 additions & 2 deletions projects/hotswap/hotswap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,51 @@
//===----------------------------------------------------------------------===//

#include "hotswap.hpp"
#include <amd_comgr.h>
#include "amd_comgr/amd_comgr.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>

namespace rocr::hotswap {

std::string GetCodeObjectIsaName(const void *elf_data, size_t elf_size) {
if (!elf_data || elf_size == 0) {
return {};
}

amd_comgr_data_t data = {0};
if (amd_comgr_create_data(AMD_COMGR_DATA_KIND_EXECUTABLE, &data) !=
AMD_COMGR_STATUS_SUCCESS) {
return {};
}

std::string isa;
if (amd_comgr_set_data(data, elf_size,
static_cast<const char *>(elf_data)) ==
AMD_COMGR_STATUS_SUCCESS) {
size_t isa_len = 0;
if (amd_comgr_get_data_isa_name(data, &isa_len, nullptr) ==
AMD_COMGR_STATUS_SUCCESS &&
isa_len > 0) {
isa.resize(isa_len);
if (amd_comgr_get_data_isa_name(data, &isa_len, isa.data()) ==
AMD_COMGR_STATUS_SUCCESS) {
// Reported size includes the terminating NUL.
if (!isa.empty() && isa.back() == '\0') {
isa.pop_back();
}
} else {
isa.clear();
}
}
}

amd_comgr_release_data(data);
return isa;
}

int RetargetCodeObject(const void *elf_data, size_t elf_size,
const char *source_isa, const char *target_isa,
void **out_data, size_t *out_size) {
Comment thread
harsh-amd marked this conversation as resolved.
Expand Down Expand Up @@ -47,7 +84,6 @@ int RetargetCodeObject(const void *elf_data, size_t elf_size,
return static_cast<int>(status);
}

// Call the hotswap rewrite API.
amd_comgr_data_t output = {0};
status = amd_comgr_hotswap_rewrite(input, source_isa, target_isa, &output);
amd_comgr_release_data(input);
Expand Down
19 changes: 15 additions & 4 deletions projects/hotswap/hotswap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,25 @@
#define ROCR_HOTSWAP_HPP

#include <cstddef>
#include <string>

namespace rocr::hotswap {

/// Rewrite a code object from source_isa to target_isa via COMGR.
/// Read a code object's own ISA name via COMGR (amd_comgr_get_data_isa_name).
///
/// Called by the hotswap tools lib when the code object's ISA differs from
/// the agent's ISA, or when stepping patches are needed (e.g., B0-to-A0).
/// Delegates to COMGR's amd_comgr_hotswap_rewrite (linked directly).
/// Uses COMGR's LLVM-canonical parser, so it tracks triple normalization
/// without hand-rolled metadata parsing. Returns an empty string on failure.
std::string GetCodeObjectIsaName(const void *elf_data, size_t elf_size);

/// Retarget a code object from source_isa to target_isa via COMGR.
///
/// Both ISA names are supplied by the caller: source_isa typically comes from
/// the code object (see GetCodeObjectIsaName) and target_isa from the running
/// GPU (e.g. the HSA agent), but either may be overridden. COMGR's
/// amd_comgr_hotswap_rewrite (linked directly) applies whatever transformation
/// the source/target pair calls for -- same-ISA stepping patches (e.g. gfx1250
/// B0 to A0) or cross-family transpilation -- and returns the rewritten code
/// object. If no transformation is needed, the output is a copy of the input.
///
/// On success, *out_data and *out_size describe the rewritten code object.
/// If *out_data differs from elf_data, it was allocated by this function
Expand Down
Loading
Loading