Files
TheRock/rocm-libraries/projects/hipdnn/tests/backend/IntegrationSetPluginUnloadingModeExt.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

199 lines
6.7 KiB
C++

// Copyright © Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include "hipdnn_backend.h"
#include <gtest/gtest.h>
#include <test_plugins/TestPluginConstants.hpp>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <fstream>
#endif
namespace
{
// Check if a shared library is currently loaded in the process
// Uses /proc/self/maps on Linux to check for loaded libraries by filename,
// GetModuleHandle on Windows
bool isSharedLibraryLoaded(const char* libraryPath)
{
#ifdef _WIN32
// On Windows, GetModuleHandle returns NULL if the module is not loaded
HMODULE handle = GetModuleHandleA(libraryPath);
return handle != nullptr;
#else
// Extract the filename from the path for matching
const std::filesystem::path path(libraryPath);
const std::string filename = path.filename().string();
// Read /proc/self/maps to find all loaded shared objects
std::ifstream maps("/proc/self/maps");
if(!maps.is_open())
{
return false;
}
std::string line;
while(std::getline(maps, line))
{
// Each line in /proc/self/maps contains the mapped file path at the end
// Check if the line contains our library filename
if(line.find(filename) != std::string::npos)
{
return true;
}
}
return false;
#endif
}
} // namespace
class IntegrationSetPluginUnloadingModeExt : public ::testing::Test
{
protected:
void SetUp() override
{
// Set up test plugin paths
const std::array<const char*, 1> paths
= {hipdnn_tests::plugin_constants::testGoodPluginPath().c_str()};
ASSERT_EQ(hipdnnSetEnginePluginPaths_ext(
paths.size(), paths.data(), HIPDNN_PLUGIN_LOADING_ABSOLUTE),
HIPDNN_STATUS_SUCCESS);
}
void TearDown() override
{
// Reset to default mode after each test
hipdnnSetPluginUnloadMode_ext(HIPDNN_DEFAULT_PLUGIN_UNLOADING_MODE);
}
static const std::string& getPluginPath()
{
return hipdnn_tests::plugin_constants::testGoodPluginPath();
}
};
TEST_F(IntegrationSetPluginUnloadingModeExt, InvalidModeReturnsBadParam)
{
const hipdnnStatus_t status
= hipdnnSetPluginUnloadMode_ext(static_cast<hipdnnPluginUnloadingMode_ext_t>(-1));
EXPECT_EQ(status, HIPDNN_STATUS_BAD_PARAM);
}
TEST_F(IntegrationSetPluginUnloadingModeExt, LazyModeKeepsPluginLoaded)
{
// Set lazy mode
hipdnnStatus_t status = hipdnnSetPluginUnloadMode_ext(HIPDNN_PLUGIN_UNLOAD_LAZY);
EXPECT_EQ(status, HIPDNN_STATUS_SUCCESS);
// Create first handle - this loads plugins
hipdnnHandle_t handle1 = nullptr;
status = hipdnnCreate(&handle1);
ASSERT_EQ(status, HIPDNN_STATUS_SUCCESS);
ASSERT_NE(handle1, nullptr);
// Plugin should now be loaded
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Destroy first handle
EXPECT_EQ(hipdnnDestroy(handle1), HIPDNN_STATUS_SUCCESS);
// In lazy mode, plugin should still be loaded after handle destruction
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Create second handle - should still be using the same loaded plugin
hipdnnHandle_t handle2 = nullptr;
status = hipdnnCreate(&handle2);
ASSERT_EQ(status, HIPDNN_STATUS_SUCCESS);
ASSERT_NE(handle2, nullptr);
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
EXPECT_EQ(hipdnnDestroy(handle2), HIPDNN_STATUS_SUCCESS);
}
TEST_F(IntegrationSetPluginUnloadingModeExt, EagerModeUnloadsPlugin)
{
// Set eager mode
hipdnnStatus_t status = hipdnnSetPluginUnloadMode_ext(HIPDNN_PLUGIN_UNLOAD_EAGER);
EXPECT_EQ(status, HIPDNN_STATUS_SUCCESS);
// Plugin should not be loaded yet (no handle created)
EXPECT_FALSE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Create first handle - this loads plugins
hipdnnHandle_t handle1 = nullptr;
status = hipdnnCreate(&handle1);
ASSERT_EQ(status, HIPDNN_STATUS_SUCCESS);
ASSERT_NE(handle1, nullptr);
// Plugin should now be loaded
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Destroy first handle - plugins unload in eager mode
EXPECT_EQ(hipdnnDestroy(handle1), HIPDNN_STATUS_SUCCESS);
// In eager mode, plugin should be unloaded after handle destruction
EXPECT_FALSE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Create second handle - should reload plugins
hipdnnHandle_t handle2 = nullptr;
status = hipdnnCreate(&handle2);
ASSERT_EQ(status, HIPDNN_STATUS_SUCCESS);
ASSERT_NE(handle2, nullptr);
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
EXPECT_EQ(hipdnnDestroy(handle2), HIPDNN_STATUS_SUCCESS);
}
TEST_F(IntegrationSetPluginUnloadingModeExt, SwitchingToEagerModeUnloadsPlugins)
{
// Start with lazy mode
hipdnnStatus_t status = hipdnnSetPluginUnloadMode_ext(HIPDNN_PLUGIN_UNLOAD_LAZY);
EXPECT_EQ(status, HIPDNN_STATUS_SUCCESS);
// Create and destroy handle in lazy mode - plugin stays loaded
hipdnnHandle_t handle1 = nullptr;
status = hipdnnCreate(&handle1);
ASSERT_EQ(status, HIPDNN_STATUS_SUCCESS);
EXPECT_EQ(hipdnnDestroy(handle1), HIPDNN_STATUS_SUCCESS);
// Plugin should still be loaded (lazy mode)
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Switch to eager mode - should unload plugins
status = hipdnnSetPluginUnloadMode_ext(HIPDNN_PLUGIN_UNLOAD_EAGER);
EXPECT_EQ(status, HIPDNN_STATUS_SUCCESS);
// Plugin should now be unloaded (no handles exist, eager mode clears persistentPmPtr)
EXPECT_FALSE(isSharedLibraryLoaded(getPluginPath().c_str()));
}
TEST_F(IntegrationSetPluginUnloadingModeExt, SetPluginPathsUnloadsPluginsInLazyMode)
{
// Start with lazy mode
hipdnnStatus_t status = hipdnnSetPluginUnloadMode_ext(HIPDNN_PLUGIN_UNLOAD_LAZY);
EXPECT_EQ(status, HIPDNN_STATUS_SUCCESS);
// Create and destroy handle - plugin stays loaded in lazy mode
hipdnnHandle_t handle1 = nullptr;
status = hipdnnCreate(&handle1);
ASSERT_EQ(status, HIPDNN_STATUS_SUCCESS);
EXPECT_EQ(hipdnnDestroy(handle1), HIPDNN_STATUS_SUCCESS);
// Plugin should still be loaded (lazy mode)
EXPECT_TRUE(isSharedLibraryLoaded(getPluginPath().c_str()));
// Set plugin paths again - should clear persistentPmPtr and unload plugins
const std::array<const char*, 1> paths
= {hipdnn_tests::plugin_constants::testExecuteFailsPluginPath().c_str()};
status = hipdnnSetEnginePluginPaths_ext(
paths.size(), paths.data(), HIPDNN_PLUGIN_LOADING_ABSOLUTE);
EXPECT_EQ(status, HIPDNN_STATUS_SUCCESS);
// Plugin should now be unloaded (setPluginPaths clears persistentPmPtr)
EXPECT_FALSE(isSharedLibraryLoaded(getPluginPath().c_str()));
}