Files
TheRock/rocm-systems/projects/hipfile/test/amd_detail/hipfile-api.cpp
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

339 lines
13 KiB
C++

/* Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
/*
* These tests are integration-level tests against the hipFile API.
* They should test that the various hipFile modules are compatible with
* one another. Running IO is not intended to be guaranteed to run here.
*
* All tests in this file are expected to pass on a CPU-only node.
*/
#include "batch/batch.h"
#include "context.h"
#include "file.h"
#include "hip.h"
#include "hipfile.h"
#include "hipfile-private.h"
#include "hipfile-test.h"
#include "hipfile-warnings.h"
#include "io.h"
#include "mbackend.h"
#include "mbatch.h"
#include "mbuffer.h"
#include "mfile.h"
#include "mhip.h"
#include "mmountinfo.h"
#include "mstate.h"
#include "msys.h"
#include "state.h"
#include <array>
#include <cerrno>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hip/hip_runtime_api.h>
#include <memory>
#include <stdexcept>
#include <sys/types.h>
#include <system_error>
#include <vector>
namespace hipFile {
struct Backend;
}
using namespace hipFile;
using namespace std;
using namespace testing;
// Put tests inside the macros to suppress the global constructor
// warnings
HIPFILE_WARN_NO_GLOBAL_CTOR_OFF
struct HipFileUnit : public HipFileUnopened {
StrictMock<MDriverState> mock_state;
void SetUp() override
{
}
};
TEST_F(HipFileUnit, TestHipFileBatchIOSetupSuccess)
{
hipFileBatchHandle_t b_handle = nullptr;
hipFileBatchHandle_t expected_b_handle = reinterpret_cast<hipFileBatchHandle_t>(0x12345678);
EXPECT_CALL(mock_state, createBatchContext).WillOnce(Return(expected_b_handle));
auto result = hipFileBatchIOSetUp(&b_handle, 1);
EXPECT_EQ(result, HIPFILE_SUCCESS);
EXPECT_EQ(b_handle, expected_b_handle);
}
TEST_F(HipFileUnit, TestHipFileBatchIOSetupBadArgument)
{
hipFileBatchHandle_t b_handle = nullptr;
EXPECT_CALL(mock_state, createBatchContext).WillOnce(Throw(std::invalid_argument("")));
auto result = hipFileBatchIOSetUp(&b_handle, 0);
EXPECT_EQ(result, HIPFILE_INVALID_VALUE);
EXPECT_EQ(b_handle, nullptr);
}
TEST_F(HipFileUnit, TestHipFileBatchIOSetupNullptrHandle)
{
auto result = hipFileBatchIOSetUp(nullptr, 1);
ASSERT_EQ(result, HIPFILE_INVALID_VALUE);
}
TEST_F(HipFileUnit, TestHipFileBatchIOSubmitSuccess)
{
hipFileBatchHandle_t b_handle = reinterpret_cast<hipFileBatchHandle_t>(0x12345678);
hipFileIOParams_t io_param;
std::shared_ptr<MBatchContext> mock_b_context = std::make_shared<MBatchContext>();
EXPECT_CALL(mock_state, getBatchContext).WillOnce(Return(mock_b_context));
EXPECT_CALL(*mock_b_context, submit_operations);
auto result = hipFileBatchIOSubmit(b_handle, 1, &io_param, 0);
ASSERT_EQ(result, HIPFILE_SUCCESS);
}
TEST_F(HipFileUnit, TestHipFileBatchIOSubmitBadHandle)
{
hipFileBatchHandle_t b_handle = nullptr;
hipFileIOParams_t io_param;
std::shared_ptr<MBatchContext> mock_b_context = std::make_shared<MBatchContext>();
EXPECT_CALL(mock_state, getBatchContext).WillOnce(Throw(InvalidBatchHandle()));
EXPECT_CALL(*mock_b_context, submit_operations).Times(0);
auto result = hipFileBatchIOSubmit(b_handle, 1, &io_param, 0);
hipFileError_t expected_result = {hipFileInvalidValue, hipSuccess};
ASSERT_EQ(result, expected_result);
}
TEST_F(HipFileUnit, TestHipFileBatchIOSubmitBadArgument)
{
hipFileBatchHandle_t b_handle = reinterpret_cast<hipFileBatchHandle_t>(0x12345678);
hipFileIOParams_t io_param;
std::shared_ptr<MBatchContext> mock_b_context = std::make_shared<MBatchContext>();
EXPECT_CALL(mock_state, getBatchContext).WillOnce(Return(mock_b_context));
EXPECT_CALL(*mock_b_context, submit_operations).WillOnce(Throw(std::invalid_argument("")));
auto result = hipFileBatchIOSubmit(b_handle, 1, &io_param, 0);
ASSERT_EQ(result, HIPFILE_INVALID_VALUE);
}
TEST_F(HipFileUnit, TestHipFileBatchIOSubmitNullptrParams)
{
hipFileBatchHandle_t b_handle = reinterpret_cast<hipFileBatchHandle_t>(0x12345678);
std::shared_ptr<MBatchContext> mock_b_context = std::make_shared<MBatchContext>();
// With nr > 0 and a nullptr iocbp, the API must reject the call before
// ever reaching the batch context (avoids dereferencing the nullptr).
EXPECT_CALL(mock_state, getBatchContext).Times(0);
EXPECT_CALL(*mock_b_context, submit_operations).Times(0);
auto result = hipFileBatchIOSubmit(b_handle, 1, nullptr, 0);
hipFileError_t expected_result = {hipFileInvalidValue, hipSuccess};
ASSERT_EQ(result, expected_result);
}
/// @brief Test hipFileIO function
struct HipFileIoParam : public TestWithParam<IoType> {
hipFileHandle_t file_handle{};
void *bufptr{reinterpret_cast<void *>(0xDEC0DE)};
size_t buflen{4096};
const void *unreg_bufptr{reinterpret_cast<void *>(0xFACEFEED)};
shared_ptr<StrictMock<MBackend>> mbackend{make_shared<StrictMock<MBackend>>()};
vector<shared_ptr<Backend>> mbackends{mbackend};
HipFileIoParam()
{
{
StrictMock<MSys> msys;
StrictMock<MLibMountHelper> mlmh;
expect_file_registration(msys, mlmh);
file_handle = Context<DriverState>::get()->registerFile(0x0BADCAFE);
}
{
StrictMock<MHip> mhip;
expect_buffer_registration(mhip, hipMemoryTypeDevice);
Context<DriverState>::get()->registerBuffer(bufptr, buflen, 0);
}
}
};
TEST_P(HipFileIoParam, HipFileIoHandlesHipPointerGetAttributesError)
{
StrictMock<MHip> mhip;
EXPECT_CALL(mhip, hipPointerGetAttributes).WillOnce(testing::Throw(Hip::RuntimeError(hipErrorUnknown)));
ASSERT_EQ(hipFileIo(GetParam(), file_handle, unreg_bufptr, 0, 0, 0, mbackends), -hipErrorUnknown);
}
TEST_P(HipFileIoParam, HipFileIoHandlesUnsupportedHipMemoryType)
{
for (const auto memoryType : UnsupportedHipMemoryTypes) {
StrictMock<MHip> mhip;
hipPointerAttribute_t attrs{};
attrs.type = memoryType;
EXPECT_CALL(mhip, hipPointerGetAttributes).WillOnce(testing::Return(attrs));
ASSERT_EQ(hipFileIo(GetParam(), file_handle, unreg_bufptr, 0, 0, 0, mbackends),
-static_cast<ssize_t>(hipFileHipMemoryTypeInvalid));
}
}
TEST_P(HipFileIoParam, HipFileIoHandlesInvalidFileHandle)
{
auto invalid_handle{reinterpret_cast<hipFileHandle_t>(0xdeadbeef)};
ASSERT_EQ(hipFileIo(GetParam(), invalid_handle, bufptr, 0, 0, 0, mbackends), -hipFileHandleNotRegistered);
}
TEST_P(HipFileIoParam, HipFileIoHandlesSysRuntimeError)
{
EXPECT_CALL(*mbackend, score).WillOnce(Return(1));
EXPECT_CALL(*mbackend, io).WillOnce(Throw(std::system_error(EBADFD, std::generic_category())));
errno = 0;
ASSERT_EQ(hipFileIo(GetParam(), file_handle, bufptr, buflen, 0, 0, mbackends), -1);
ASSERT_EQ(errno, EBADFD);
}
TEST_P(HipFileIoParam, HipFileIoHandlesHipRuntimeError)
{
EXPECT_CALL(*mbackend, score).WillOnce(Return(1));
EXPECT_CALL(*mbackend, io).WillOnce(Throw(Hip::RuntimeError(hipErrorUnknown)));
ASSERT_EQ(hipFileIo(GetParam(), file_handle, bufptr, buflen, 0, 0, mbackends), -hipErrorUnknown);
}
TEST_P(HipFileIoParam, HipFileIoHandlesInvalidArgumentError)
{
EXPECT_CALL(*mbackend, score).WillOnce(Return(1));
EXPECT_CALL(*mbackend, io).WillOnce(Throw(std::invalid_argument("")));
ASSERT_EQ(hipFileIo(GetParam(), file_handle, bufptr, buflen, 0, 0, mbackends), -hipFileInvalidValue);
}
TEST_P(HipFileIoParam, HipFileIoHandlesBackendDisabled)
{
EXPECT_CALL(*mbackend, score).WillOnce(Return(1));
EXPECT_CALL(*mbackend, io).WillOnce(Throw(BackendDisabled()));
ASSERT_EQ(hipFileIo(GetParam(), file_handle, bufptr, buflen, 0, 0, mbackends), -hipFileInternalError);
}
INSTANTIATE_TEST_SUITE_P(HipFileIo, HipFileIoParam, Values(IoType::Read, IoType::Write));
struct HipFileIoBackendSelectionParam : public ::testing::TestWithParam<IoType> {
IoType io_type;
hipFileHandle_t handle;
void *buffer;
size_t io_size;
hoff_t file_offset;
hoff_t buffer_offset;
int flags;
std::shared_ptr<StrictMock<MFile>> mfile;
std::shared_ptr<StrictMock<MBuffer>> mbuffer;
std::shared_ptr<StrictMock<MBackend>> mbe1;
std::shared_ptr<StrictMock<MBackend>> mbe2;
std::shared_ptr<StrictMock<MBackend>> mbe3;
StrictMock<MDriverState> mds;
HipFileIoBackendSelectionParam()
: io_type{GetParam()}, handle{reinterpret_cast<hipFileHandle_t>(0xBADF00D)},
buffer{reinterpret_cast<void *>(0xDEADBEEF)}, io_size{1024}, file_offset{32}, buffer_offset{64},
flags{0}, mfile{std::make_shared<StrictMock<MFile>>()},
mbuffer{std::make_shared<StrictMock<MBuffer>>()}, mbe1{std::make_shared<StrictMock<MBackend>>()},
mbe2{std::make_shared<StrictMock<MBackend>>()}, mbe3{std::make_shared<StrictMock<MBackend>>()}
{
}
};
TEST_P(HipFileIoBackendSelectionParam, HipFileIoThrowsIfThereAreNoBackends)
{
auto backends{std::vector<std::shared_ptr<Backend>>()};
EXPECT_CALL(mds, getFileAndBuffer(handle, buffer)).WillOnce(Return(file_buffer_pair{mfile, mbuffer}));
EXPECT_CALL(mds, getBackends).WillOnce(Return(std::move(backends)));
switch (io_type) {
case IoType::Read:
ASSERT_EQ(hipFileRead(handle, buffer, io_size, file_offset, buffer_offset),
-hipFileInternalError);
break;
case IoType::Write:
ASSERT_EQ(hipFileWrite(handle, buffer, io_size, file_offset, buffer_offset),
-hipFileInternalError);
break;
default:
FAIL() << "Unhandled IO Type";
}
}
TEST_P(HipFileIoBackendSelectionParam, HipFileIoThrowsIfAllBackendsRejectTheIO)
{
std::vector<std::shared_ptr<Backend>> backends{mbe1, mbe2, mbe3};
EXPECT_CALL(mds, getFileAndBuffer(handle, buffer)).WillOnce(Return(file_buffer_pair{mfile, mbuffer}));
EXPECT_CALL(mds, getBackends).WillOnce(Return(std::move(backends)));
EXPECT_CALL(*mbe1, score(Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(-1));
EXPECT_CALL(*mbe2, score(Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(-1));
EXPECT_CALL(*mbe3, score(Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(-1));
switch (io_type) {
case IoType::Read:
ASSERT_EQ(hipFileRead(handle, buffer, io_size, file_offset, buffer_offset),
-hipFileInternalError);
break;
case IoType::Write:
ASSERT_EQ(hipFileWrite(handle, buffer, io_size, file_offset, buffer_offset),
-hipFileInternalError);
break;
default:
FAIL() << "Unhandled IO Type";
}
}
TEST_P(HipFileIoBackendSelectionParam, HipFileIoIssuesIoToHighestScoringBackend)
{
std::vector<std::shared_ptr<Backend>> backends{mbe1, mbe2, mbe3};
EXPECT_CALL(mds, getFileAndBuffer(handle, buffer)).WillOnce(Return(file_buffer_pair{mfile, mbuffer}));
EXPECT_CALL(mds, getBackends).WillOnce(Return(std::move(backends)));
EXPECT_CALL(*mbe1, score(Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(0));
EXPECT_CALL(*mbe2, score(Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(2));
EXPECT_CALL(*mbe3, score(Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(1));
switch (io_type) {
case IoType::Read:
EXPECT_CALL(*mbe2,
io(Eq(IoType::Read), Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(io_size));
ASSERT_EQ(hipFileRead(handle, buffer, io_size, file_offset, buffer_offset), io_size);
break;
case IoType::Write:
EXPECT_CALL(*mbe2,
io(Eq(IoType::Write), Eq(mfile), Eq(mbuffer), io_size, file_offset, buffer_offset))
.WillOnce(Return(io_size));
ASSERT_EQ(hipFileWrite(handle, buffer, io_size, file_offset, buffer_offset), io_size);
break;
default:
FAIL() << "Unhandled IO Type";
}
}
INSTANTIATE_TEST_SUITE_P(HipFileIoBackendSelection, HipFileIoBackendSelectionParam,
::testing::Values(IoType::Read, IoType::Write));
HIPFILE_WARN_NO_GLOBAL_CTOR_ON