Add Catecholamine (CA), a tool for breaking code objects out of fat binaries created via LPL. As with LPL, --help provides usage details. Fixed LPL's implementation of path_to_self which was a nasty infinite loop iff for whatever reason readlink would always fail, orthogonally to the string's size. Link against pthread for LPL, which uses call_once and once_flag (this could, under certain circumstances, yield an arcane "Unknown error=-1" exception.
This commit is contained in:
@@ -144,6 +144,13 @@ if (BUILD_HIPIFY_CLANG)
|
||||
add_subdirectory(hipify-clang)
|
||||
endif()
|
||||
|
||||
# Build LPL an CA (fat binary generation / fat binary decomposition tools) if
|
||||
# platform is hcc; do this before the ugly hijacking of the compiler, since no
|
||||
# HC code is involved.
|
||||
if (HIP_PLATFORM STREQUAL "hcc")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/LPL_CA)
|
||||
endif ()
|
||||
|
||||
# Build hip_hcc if platform is hcc
|
||||
if(HIP_PLATFORM STREQUAL "hcc")
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
@@ -191,7 +198,7 @@ if(HIP_PLATFORM STREQUAL "hcc")
|
||||
src/math_functions.cpp)
|
||||
|
||||
execute_process(COMMAND ${HCC_HOME}/bin/hcc-config --ldflags OUTPUT_VARIABLE HCC_LD_FLAGS)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${HCC_LD_FLAGS} -Wl,-Bsymbolic")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${HCC_LD_FLAGS}")
|
||||
#find_package(LLVM HINTS ${HCC_HOME}/compiler/lib/cmake)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --amdgpu-target=gfx701 --amdgpu-target=gfx801 --amdgpu-target=gfx802 --amdgpu-target=gfx803 --amdgpu-target=gfx900")
|
||||
if(COMPILE_HIP_ATP_MARKER)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
add_executable(lpl lpl.cpp)
|
||||
set_target_properties(
|
||||
lpl PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS OFF
|
||||
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
target_include_directories(lpl PUBLIC ${PROJECT_SOURCE_DIR}/src)
|
||||
# Install LPL if platform is hcc
|
||||
if (HIP_PLATFORM STREQUAL "hcc")
|
||||
install(TARGETS lpl RUNTIME DESTINATION bin)
|
||||
endif ()
|
||||
@@ -0,0 +1,32 @@
|
||||
#-------------------------------------LPL--------------------------------------#
|
||||
add_executable(lpl lpl.cpp)
|
||||
set_target_properties(
|
||||
lpl PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS OFF
|
||||
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
target_include_directories(lpl PUBLIC ${PROJECT_SOURCE_DIR}/src)
|
||||
target_compile_options(lpl PUBLIC -Wall)
|
||||
target_link_libraries(lpl PUBLIC pthread)
|
||||
|
||||
install(TARGETS lpl RUNTIME DESTINATION bin)
|
||||
#-------------------------------------LPL--------------------------------------#
|
||||
|
||||
#-------------------------------------CA---------------------------------------#
|
||||
add_executable(ca ca.cpp ${PROJECT_SOURCE_DIR}/src/code_object_bundle.cpp)
|
||||
set_target_properties(
|
||||
ca PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS OFF
|
||||
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
target_include_directories(ca SYSTEM PUBLIC ${HSA_PATH}/include)
|
||||
target_include_directories(ca PUBLIC ${PROJECT_SOURCE_DIR}/src)
|
||||
find_library(
|
||||
hsart NAMES libhsa-runtime64.so libhsa-runtime64.so.1 HINTS ${HSA_PATH}/lib)
|
||||
target_link_libraries(ca PUBLIC ${hsart})
|
||||
target_compile_options(ca PUBLIC -Wall)
|
||||
|
||||
install(TARGETS ca RUNTIME DESTINATION bin)
|
||||
#-------------------------------------CA---------------------------------------#
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "ca.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace clara;
|
||||
using namespace hip_impl;
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try {
|
||||
bool help = false;
|
||||
vector<string> inputs;
|
||||
string targets;
|
||||
|
||||
auto cmd = cmdline_parser(help, inputs, targets);
|
||||
|
||||
const auto r = cmd.parse(Args{argc, argv});
|
||||
|
||||
if (!r) throw runtime_error{r.errorMessage()};
|
||||
|
||||
if (help) cout << cmd << endl;
|
||||
else {
|
||||
if (inputs.empty()) throw runtime_error{"No inputs specified."};
|
||||
|
||||
validate_inputs(inputs);
|
||||
|
||||
auto tmp = tokenize_targets(targets);
|
||||
if (tmp.empty()) {
|
||||
tmp.assign(amdgpu_targets().cbegin(), amdgpu_targets().cend());
|
||||
}
|
||||
else validate_targets(tmp);
|
||||
|
||||
extract_code_objects(inputs, tmp);
|
||||
}
|
||||
}
|
||||
catch (const exception& ex) {
|
||||
cerr << ex.what() << endl;
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include "../include/hip/hcc_detail/code_object_bundle.hpp"
|
||||
|
||||
#include "clara/clara.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hip_impl
|
||||
{
|
||||
inline
|
||||
clara::Parser cmdline_parser(
|
||||
bool& help,
|
||||
std::vector<std::string>& inputs,
|
||||
std::string& targets)
|
||||
{
|
||||
return
|
||||
clara::Help{help} |
|
||||
clara::Arg{inputs, "a" + fat_binary_extension() + " etc."}(
|
||||
"fat binaries which contain the code objects to be extracted; "
|
||||
"the binary format of the file(s) is documented at: "
|
||||
"https://reviews.llvm.org/D13909; "
|
||||
"the code object format is documented at: "
|
||||
"https://www.llvm.org/docs/AMDGPUUsage.html#code-object.") |
|
||||
clara::Opt{targets, "gfx803,gfx900 etc."}
|
||||
["-t"]["--targets"](
|
||||
"targets for which code objects are to be extracted from "
|
||||
"the fat binary; must be included in the set of processors "
|
||||
"with ROCm support from "
|
||||
"https://www.llvm.org/docs/AMDGPUUsage.html#processors.");
|
||||
}
|
||||
|
||||
inline
|
||||
std::string make_code_object_file_name(
|
||||
const std::string& input, const std::string& target)
|
||||
{
|
||||
assert(!input.empty() && !target.empty());
|
||||
|
||||
auto r = input.substr(0, input.find(fat_binary_extension()));
|
||||
r += '_' + target + code_object_extension();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
void extract_code_objects(
|
||||
const std::vector<std::string>& inputs,
|
||||
const std::vector<std::string>& targets)
|
||||
{
|
||||
for (auto&& input : inputs) {
|
||||
std::ifstream tmp{input};
|
||||
std::vector<char> bundle{
|
||||
std::istreambuf_iterator<char>{tmp},
|
||||
std::istreambuf_iterator<char>{}};
|
||||
|
||||
Bundled_code_header tmp1{bundle};
|
||||
|
||||
if (!valid(tmp1)) {
|
||||
throw std::runtime_error{input + " is not a valid fat binary."};
|
||||
}
|
||||
|
||||
for (auto&& target : targets) {
|
||||
const auto it = std::find_if(
|
||||
bundles(tmp1).cbegin(),
|
||||
bundles(tmp1).cend(),
|
||||
[&](const Bundled_code& x) {
|
||||
return x.triple.find(target) != std::string::npos;
|
||||
});
|
||||
|
||||
if (it == bundles(tmp1).cend()) {
|
||||
std::cerr << "Warning: " << input
|
||||
<< " does not contain code for the " << target
|
||||
<< " target.";
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ofstream out{make_code_object_file_name(input, target)};
|
||||
std::copy_n(
|
||||
it->blob.cbegin(),
|
||||
it->blob.size(),
|
||||
std::ostreambuf_iterator<char>{out});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void validate_inputs(const std::vector<std::string>& inputs)
|
||||
{
|
||||
const auto it = std::find_if_not(
|
||||
inputs.cbegin(), inputs.cend(), file_exists);
|
||||
|
||||
if (it != inputs.cend()) {
|
||||
throw std::runtime_error{
|
||||
"Non existent file " + *it + " passed as input."};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace hip_impl
|
||||
{
|
||||
inline
|
||||
const std::unordered_set<std::string>& amdgpu_targets()
|
||||
{ // The evolving list lives at:
|
||||
// https://www.llvm.org/docs/AMDGPUUsage.html#processors.
|
||||
static const std::unordered_set<std::string> r{
|
||||
"gfx701", "gfx801", "gfx802", "gfx803", "gfx900"};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
const std::string& code_object_extension()
|
||||
{
|
||||
static const std::string r{".ffa"};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
const std::string& fat_binary_extension()
|
||||
{
|
||||
static const std::string r{".adipose"};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
bool file_exists(const std::string& path_to)
|
||||
{
|
||||
return static_cast<bool>(std::ifstream{path_to});
|
||||
}
|
||||
|
||||
inline
|
||||
std::vector<std::string> tokenize_targets(const std::string& x)
|
||||
{ // TODO: move to regular expressions once we clarify the need to support
|
||||
// ancient standard library implementations.
|
||||
if (x.empty()) return {};
|
||||
|
||||
static constexpr const char valid_characters[] = "gfx0123456789,";
|
||||
|
||||
if (x.find_first_not_of(valid_characters) != std::string::npos) {
|
||||
throw std::runtime_error{"Invalid target string: " + x};
|
||||
}
|
||||
|
||||
std::vector<std::string> r;
|
||||
|
||||
auto it = x.cbegin();
|
||||
do {
|
||||
auto it1 = std::find(it, x.cend(), ',');
|
||||
r.emplace_back(it, it1);
|
||||
|
||||
if (it1 == x.cend()) break;
|
||||
|
||||
it = ++it1;
|
||||
} while (true);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
void validate_targets(const std::vector<std::string>& x)
|
||||
{
|
||||
assert(!x.empty());
|
||||
|
||||
for (auto&& t : x) {
|
||||
static const std::string digits{"0123456789"};
|
||||
static const std::string pre{"gfx"};
|
||||
|
||||
if (t.find(pre) != 0 ||
|
||||
t.find_first_not_of(digits, pre.size()) != std::string::npos) {
|
||||
throw std::runtime_error{"Invalid target: " + t};
|
||||
}
|
||||
|
||||
if (amdgpu_targets().find(t) == amdgpu_targets().cend()) {
|
||||
std::cerr << "Warning: target " << t
|
||||
<< " has not been validated yet; it may be invalid."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // Namespace hip_impl.
|
||||
@@ -1,3 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include "clara/clara.hpp"
|
||||
#include "pstreams/pstream.h"
|
||||
#include "../src/elfio/elfio.hpp"
|
||||
@@ -11,29 +15,11 @@
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace hip_impl
|
||||
{
|
||||
inline
|
||||
const std::unordered_set<std::string>& amdgpu_targets()
|
||||
{ // The evolving list lives at:
|
||||
// https://www.llvm.org/docs/AMDGPUUsage.html#processors.
|
||||
static const std::unordered_set<std::string> r{
|
||||
"gfx701", "gfx801", "gfx802", "gfx803", "gfx900"};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
const std::string& fat_binary_extension()
|
||||
{
|
||||
static const std::string r{".adipose"};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
const std::string& kernel_section()
|
||||
{
|
||||
@@ -47,16 +33,20 @@ namespace hip_impl
|
||||
{
|
||||
static constexpr const char self[] = "/proc/self/exe";
|
||||
|
||||
static std::string r(PATH_MAX, '\0');
|
||||
static std::string r;
|
||||
static std::once_flag f;
|
||||
|
||||
std::call_once(f, []() {
|
||||
decltype(readlink(self, &r.front(), r.size())) read_cnt;
|
||||
do {
|
||||
read_cnt = readlink(self, &r.front(), r.size());
|
||||
} while (read_cnt == -1);
|
||||
using N = decltype(readlink(self, &r.front(), r.size()));
|
||||
|
||||
r.resize(read_cnt);
|
||||
constexpr decltype(r.size()) max_path_sz{PATH_MAX};
|
||||
N read_cnt;
|
||||
do {
|
||||
r.resize(std::max(2 * r.size(), max_path_sz));
|
||||
read_cnt = readlink(self, &r.front(), r.size());
|
||||
} while (read_cnt == -1 && r.size() < r.max_size());
|
||||
|
||||
r.resize(std::max(read_cnt, N{0}));
|
||||
});
|
||||
|
||||
return r;
|
||||
@@ -155,12 +145,6 @@ namespace hip_impl
|
||||
copy_kernel_section_to_fat_binary(*tmp, output);
|
||||
}
|
||||
|
||||
inline
|
||||
bool file_exists(const std::string& path_to)
|
||||
{
|
||||
return static_cast<bool>(std::ifstream{path_to});
|
||||
}
|
||||
|
||||
inline
|
||||
bool hipcc_and_lpl_colocated()
|
||||
{
|
||||
@@ -169,55 +153,6 @@ namespace hip_impl
|
||||
return file_exists(path_to_hipcc());
|
||||
}
|
||||
|
||||
inline
|
||||
std::vector<std::string> tokenize_targets(const std::string& x)
|
||||
{ // TODO: move to regular expressions once we clarify the need to support
|
||||
// ancient standard library implementations.
|
||||
if (x.empty()) return {};
|
||||
|
||||
static constexpr const char valid_characters[] = "gfx0123456789,";
|
||||
|
||||
if (x.find_first_not_of(valid_characters) != std::string::npos) {
|
||||
throw std::runtime_error{"Invalid target string: " + x};
|
||||
}
|
||||
|
||||
std::vector<std::string> r;
|
||||
|
||||
auto it = x.cbegin();
|
||||
do {
|
||||
auto it1 = std::find(it, x.cend(), ',');
|
||||
r.emplace_back(it, it1);
|
||||
|
||||
if (it1 == x.cend()) break;
|
||||
|
||||
it = ++it1;
|
||||
} while (true);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
void validate_targets(const std::vector<std::string>& x)
|
||||
{
|
||||
assert(!x.empty());
|
||||
|
||||
for (auto&& t : x) {
|
||||
static const std::string digits{"0123456789"};
|
||||
static const std::string pre{"gfx"};
|
||||
|
||||
if (t.find(pre) != 0 ||
|
||||
t.find_first_not_of(digits, pre.size()) != std::string::npos) {
|
||||
throw std::runtime_error{"Invalid target: " + t};
|
||||
}
|
||||
|
||||
if (amdgpu_targets().find(t) == amdgpu_targets().cend()) {
|
||||
std::cerr << "Warning: target " << t
|
||||
<< " has not been validated yet; it may be invalid."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
clara::Parser cmdline_parser(
|
||||
bool& help,
|
||||
@@ -239,8 +174,8 @@ namespace hip_impl
|
||||
"inputs for compilation; must contain valid C++ code.") |
|
||||
clara::Opt{targets, "gfx803,gfx900 etc."}
|
||||
["-t"]["--targets"](
|
||||
"targets for AMDGPU lowering; must be one of the processors"
|
||||
" with ROCm support from "
|
||||
"targets for AMDGPU lowering; must be included in the set "
|
||||
"of processors with ROCm support from "
|
||||
"https://www.llvm.org/docs/AMDGPUUsage.html#processors.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user