CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
219 lines
6.3 KiB
C++
219 lines
6.3 KiB
C++
/* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "ais-capability.h"
|
|
|
|
#include "hip.h"
|
|
#include "hipfile.h"
|
|
|
|
#include <charconv>
|
|
#include <cerrno>
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace hipFile::test {
|
|
|
|
namespace {
|
|
|
|
// BIT6 of the KFD topology node "capability" field signals that amdgpu has
|
|
// initialized AIS on that node, implying the kernel supports P2PDMA.
|
|
constexpr uint64_t KFD_AIS_CAPABILITY_BIT = 0x40;
|
|
|
|
}
|
|
|
|
void
|
|
AisCapability::detectKernelAis()
|
|
{
|
|
const std::string topology_nodes = "/sys/class/kfd/kfd/topology/nodes";
|
|
|
|
bool any_gpu = false;
|
|
|
|
std::error_code ec;
|
|
auto node = std::filesystem::directory_iterator{topology_nodes, ec};
|
|
const auto end = std::filesystem::directory_iterator{};
|
|
for (; !ec && node != end; node.increment(ec)) {
|
|
const auto properties_path = node->path() / "properties";
|
|
std::ifstream in{properties_path};
|
|
if (!in.is_open()) {
|
|
continue;
|
|
}
|
|
|
|
uint64_t capability = 0;
|
|
uint32_t simd_count = 0;
|
|
std::string line;
|
|
while (std::getline(in, line)) {
|
|
std::istringstream fields{line};
|
|
std::string key;
|
|
std::string value_text;
|
|
if (!(fields >> key >> value_text) || (key != "capability" && key != "simd_count")) {
|
|
continue;
|
|
}
|
|
|
|
uint64_t value = 0;
|
|
auto [last, parse_error] =
|
|
std::from_chars(value_text.data(), value_text.data() + value_text.size(), value);
|
|
if (parse_error != std::errc{} || last != value_text.data() + value_text.size()) {
|
|
continue;
|
|
}
|
|
|
|
if (key == "capability") {
|
|
capability = value;
|
|
}
|
|
else if (value <= std::numeric_limits<uint32_t>::max()) {
|
|
simd_count = static_cast<uint32_t>(value);
|
|
}
|
|
}
|
|
|
|
if (simd_count == 0) {
|
|
continue; // Not a GPU, disregard
|
|
}
|
|
any_gpu = true;
|
|
if ((capability & KFD_AIS_CAPABILITY_BIT) == 0) {
|
|
kernel_ais = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
kernel_ais = any_gpu;
|
|
}
|
|
|
|
void
|
|
AisCapability::detectHipRuntime()
|
|
{
|
|
hip_runtime = hipFile::getHipAmdFileReadPtr() != nullptr && hipFile::getHipAmdFileWritePtr() != nullptr;
|
|
}
|
|
|
|
void
|
|
AisCapability::detectAmdgpu()
|
|
{
|
|
std::ifstream kallsyms{"/proc/kallsyms"};
|
|
if (!kallsyms.is_open()) {
|
|
std::cerr << "Unable to open /proc/kallsyms\n";
|
|
amdgpu = false;
|
|
return;
|
|
}
|
|
|
|
std::string line;
|
|
while (std::getline(kallsyms, line)) {
|
|
if (line.find("kfd_ais_rw_file") != std::string::npos) {
|
|
amdgpu = true;
|
|
return;
|
|
}
|
|
}
|
|
amdgpu = false;
|
|
}
|
|
|
|
void
|
|
AisCapability::detectIoProbe(hipFileHandle_t handle, void *device_buffer)
|
|
{
|
|
#if HIP_VERSION_MAJOR > 7 || (HIP_VERSION_MAJOR == 7 && HIP_VERSION_MINOR >= 14)
|
|
errno = 0;
|
|
ssize_t ret = hipFileRead(handle, device_buffer, /*size=*/0, /*file_offset=*/0, /*buffer_offset=*/0);
|
|
io_probe_ret = ret;
|
|
io_probe_errno = errno;
|
|
io_probe = classifyIoProbe(ret, errno);
|
|
#else
|
|
// Avoid unused argument compiler warning.
|
|
static_cast<void>(handle);
|
|
static_cast<void>(device_buffer);
|
|
io_probe = IoProbeResult::NotRun;
|
|
#endif
|
|
}
|
|
|
|
AisCapability::IoProbeResult
|
|
AisCapability::classifyIoProbe(ssize_t ret, int err)
|
|
{
|
|
if (ret == 0) {
|
|
return IoProbeResult::Ok;
|
|
}
|
|
if (ret == -1 && err == ENODEV) {
|
|
return IoProbeResult::NoDevice;
|
|
}
|
|
if (ret == -static_cast<ssize_t>(hipFileInternalError)) {
|
|
return IoProbeResult::InternalError;
|
|
}
|
|
return IoProbeResult::OtherError;
|
|
}
|
|
|
|
const char *
|
|
AisCapability::ioProbeReason(IoProbeResult result)
|
|
{
|
|
switch (result) {
|
|
case IoProbeResult::NotRun:
|
|
return "not run (zero-sized I/O probe unavailable)";
|
|
case IoProbeResult::Ok:
|
|
return "ok";
|
|
case IoProbeResult::NoDevice:
|
|
return "ENODEV: storage not on a P2PDMA-capable NVMe device (e.g. lvm/md "
|
|
"volume), AIS not initialized on the device, or pcie_p2pdma_distance < 0";
|
|
case IoProbeResult::InternalError:
|
|
return "fastpath rejected the request (unsupported filesystem, misaligned I/O, "
|
|
"or non-device buffer)";
|
|
case IoProbeResult::OtherError:
|
|
return "unexpected error (zero-sized I/O may be unsupported)";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
AisCapability::GateDecision
|
|
AisCapability::populate(hipFileHandle_t handle, void *device_buffer)
|
|
{
|
|
static const AisCapability static_capability = [] {
|
|
AisCapability capability{false};
|
|
capability.detectKernelAis();
|
|
capability.detectHipRuntime();
|
|
capability.detectAmdgpu();
|
|
return capability;
|
|
}();
|
|
|
|
kernel_ais = static_capability.kernel_ais;
|
|
hip_runtime = static_capability.hip_runtime;
|
|
amdgpu = static_capability.amdgpu;
|
|
detectIoProbe(handle, device_buffer);
|
|
|
|
if (fastpathAvailable()) {
|
|
return GateDecision::Run;
|
|
}
|
|
return allow_skip ? GateDecision::Skip : GateDecision::Fail;
|
|
}
|
|
|
|
std::string
|
|
AisCapability::report() const
|
|
{
|
|
auto pass_fail = [](bool ok) { return ok ? "Pass" : "Fail"; };
|
|
|
|
std::ostringstream os;
|
|
os << "Fastpath Validation:\n";
|
|
os << " HIP Runtime Check: " << pass_fail(hip_runtime) << "\n";
|
|
os << " amdgpu Check: " << pass_fail(amdgpu) << "\n";
|
|
os << " AIS init check: " << pass_fail(kernel_ais) << "\n";
|
|
|
|
const char *io_status =
|
|
io_probe == IoProbeResult::Ok ? "Pass" : (io_probe == IoProbeResult::NotRun ? "Skipped" : "Fail");
|
|
os << " Test I/O check: " << io_status;
|
|
if (io_probe != IoProbeResult::Ok && io_probe != IoProbeResult::NotRun) {
|
|
os << " (" << ioProbeReason(io_probe) << "; ret=" << io_probe_ret << ", errno=" << io_probe_errno
|
|
<< ")";
|
|
}
|
|
|
|
return os.str();
|
|
}
|
|
|
|
std::string
|
|
AisCapability::skipHint() const
|
|
{
|
|
return "To skip these tests instead of failing, configure the build with "
|
|
"-DHIPFILE_ALLOW_SKIP_FASTPATH_TESTS=ON "
|
|
"(passes --allow-skip-fastpath to the system test binary).";
|
|
}
|
|
|
|
}
|