Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
37111be
[hipDNN] Plugin SDK + Device Properties Infrastructure (RFC 0007 - Pa…
cderb Apr 15, 2026
1e54ffb
Fix RFC references to include RFC 0007 prefix
cderb Apr 15, 2026
1e19a4d
Add missing HipdnnException.hpp include to TestDeviceProperties
cderb Apr 15, 2026
18d094a
Add RFC 0007 documentation
cderb Apr 15, 2026
49f6188
Apply code quality and ABI fixes to PR1 Plugin SDK infrastructure
cderb Apr 16, 2026
5856d6e
Add unit tests for RFC 0007 Part 1 Plugin SDK infrastructure
cderb Apr 16, 2026
2da1d23
formatting corrections
cderb Apr 16, 2026
853b064
Fix pre-commit hook failures
cderb Apr 16, 2026
05af187
fix generated files
cderb Apr 16, 2026
78bd506
Merge remote-tracking branch 'origin/develop' into users/cderb/rfc000…
cderb Apr 17, 2026
5ff2578
add more coverage tests
cderb Apr 17, 2026
f1c3f8e
format on test files
cderb Apr 17, 2026
98b1892
Add comprehensive HeuristicPlugin test coverage
cderb Apr 17, 2026
e2a17a6
Fixed race condition in heuristic plugin initialization.
cderb Apr 18, 2026
5947d05
format
cderb Apr 20, 2026
35c2155
reorganize heuristic plugin tests, reduce test files, add to plugin m…
cderb Apr 20, 2026
aeb7d54
remove special unicode characters
cderb Apr 20, 2026
359c8aa
Require policy names and compute policy IDs from names
cderb Apr 20, 2026
59a692c
Add architectureName to device properties for LLVM architecture support
cderb Apr 20, 2026
6a24652
revert EngineOrdering changes, will re-investigate need in part 2
cderb Apr 20, 2026
c40cf35
format
cderb Apr 20, 2026
b8c2eda
format
cderb Apr 20, 2026
e98e1a6
fix directory resolution for heuristic plugin ci test
cderb Apr 20, 2026
08429e3
nolints
cderb Apr 20, 2026
4187f50
format
cderb Apr 20, 2026
0dde900
Merge remote-tracking branch 'origin/develop' into users/cderb/rfc000…
cderb Apr 21, 2026
1b97bb9
addressing reviews
cderb Apr 21, 2026
cc61d02
use weak ptr to track heuristic plugin manager resources
cderb Apr 21, 2026
59e6ae6
format
cderb Apr 21, 2026
bb298a7
remove heuristicLoggingCallback and use backendLoggingCallback directly
cderb Apr 21, 2026
94b9680
update patch version
cderb Apr 21, 2026
d9763c2
makelist corrections
cderb Apr 21, 2026
ee29b1c
corrections for MockHeuristicPlugin, add virtual to HeuristicPlugin m…
cderb Apr 21, 2026
348e797
review comments
cderb Apr 21, 2026
7e837d2
add PluginResourceManagerBase
cderb Apr 21, 2026
9145dbb
format
cderb Apr 21, 2026
86f19ad
windows test fix
cderb Apr 22, 2026
45d57b3
refactor HeuristicsPluginApi to extend PluginApi
cderb Apr 22, 2026
f14da60
windows friendly test paths
cderb Apr 22, 2026
72a83c0
fix test
cderb Apr 23, 2026
3eb163b
Fix test for windows path names
jdcampbe Apr 23, 2026
2917710
Fix SharedLibrary move losing _libraryPath after std::move
jdcampbe Apr 23, 2026
8f674e6
format
cderb Apr 23, 2026
4a1bb70
tidy fix
cderb Apr 23, 2026
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: 2 additions & 0 deletions projects/hipdnn/backend/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ add_library(
FlatbufferUtilities.cpp
plugin/EnginePlugin.cpp
plugin/EnginePluginResourceManager.cpp
plugin/HeuristicPlugin.cpp
plugin/HeuristicPluginResourceManager.cpp
plugin/PluginCore.cpp
plugin/SharedLibrary.cpp
utilities/EngineOrdering.cpp
Expand Down
7 changes: 7 additions & 0 deletions projects/hipdnn/backend/src/handle/Handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ using namespace hipdnn_backend::plugin;

hipdnnHandle::hipdnnHandle()
: _pluginResourceManager(EnginePluginResourceManager::create())
Comment thread
cderb marked this conversation as resolved.
, _heuristicPluginResourceManager(HeuristicPluginResourceManager::create())
{
}

Expand All @@ -27,6 +28,12 @@ std::shared_ptr<EnginePluginResourceManager> hipdnnHandle::getPluginResourceMana
return _pluginResourceManager;
}

std::shared_ptr<HeuristicPluginResourceManager>
hipdnnHandle::getHeuristicPluginResourceManager() const
{
return _heuristicPluginResourceManager;
}

size_t hipdnnHandle::getEngineCount() const
{
return _pluginResourceManager->getEngineCount();
Expand Down
5 changes: 5 additions & 0 deletions projects/hipdnn/backend/src/handle/Handle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include "plugin/EnginePluginResourceManager.hpp"
#include "plugin/HeuristicPluginResourceManager.hpp"
#include <cstdint>
#include <hip/hip_runtime.h>
#include <memory>
Expand All @@ -20,13 +21,17 @@ struct hipdnnHandle // NOLINT
virtual hipStream_t getStream() const;
virtual std::shared_ptr<hipdnn_backend::plugin::EnginePluginResourceManager>
getPluginResourceManager() const;
virtual std::shared_ptr<hipdnn_backend::plugin::HeuristicPluginResourceManager>
getHeuristicPluginResourceManager() const;
virtual size_t getEngineCount() const;
virtual std::vector<hipdnn_backend::plugin::EngineInfo> getEngineInfos() const;
virtual std::string toString() const;

private:
hipStream_t _stream = nullptr;
std::shared_ptr<hipdnn_backend::plugin::EnginePluginResourceManager> _pluginResourceManager;
std::shared_ptr<hipdnn_backend::plugin::HeuristicPluginResourceManager>
_heuristicPluginResourceManager;
};

template <>
Expand Down
10 changes: 10 additions & 0 deletions projects/hipdnn/backend/src/logging/Logging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@
hipdnn_backend::logging::detail::K_BACKEND_LOGGER_COMPONENT_NAME, \
hipdnn_backend::logging::detail::formatBackendMessage(__VA_ARGS__)); \
} while(0)

// DEBUG logging - use INFO level since DEBUG doesn't exist in SDK
#define HIPDNN_BACKEND_LOG_DEBUG(...) \
do \
{ \
hipdnn_backend::logging::initialize(); \
HIPDNN_SDK_LOG_INFO_WITH_COMPONENT( \
hipdnn_backend::logging::detail::K_BACKEND_LOGGER_COMPONENT_NAME, \
hipdnn_backend::logging::detail::formatBackendMessage(__VA_ARGS__)); \
} while(0)
#endif // HIPDNN_BACKEND_COMPILATION

namespace hipdnn_backend::logging
Expand Down
213 changes: 58 additions & 155 deletions projects/hipdnn/backend/src/plugin/EnginePluginResourceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,76 +27,55 @@ namespace plugin
namespace
{

struct PluginLoadingConfig
// Static storage for engine plugin configuration
std::mutex gEngineMutex;
PluginLoadingConfig gEngineConfig;
std::weak_ptr<EnginePluginManager> gEngineWeakPtr;
std::shared_ptr<EnginePluginManager> gEnginePersistentPtr;
std::atomic<bool> gEngineShutdownFlag{false};

// Register atexit handler to set shutdown flag
struct EnginePluginShutdownRegistrar
{
std::set<std::filesystem::path> paths;
hipdnnPluginLoadingMode_ext_t mode = HIPDNN_DEFAULT_PLUGIN_LOADING_MODE;
hipdnnPluginUnloadingMode_ext_t unloadingMode = HIPDNN_DEFAULT_PLUGIN_UNLOADING_MODE;
EnginePluginShutdownRegistrar()
{
std::atexit([]() { gEngineShutdownFlag.store(true, std::memory_order_release); });
}
};

std::mutex pluginMutex;
PluginLoadingConfig pluginConfig;
std::weak_ptr<EnginePluginManager> pmPtr;
// Keeps EnginePluginManager alive in lazy unloading mode
std::shared_ptr<EnginePluginManager> persistentPmPtr;
EnginePluginShutdownRegistrar gEngineShutdownRegistrar;

} // namespace

void EnginePluginResourceManager::setPluginLogLevel(hipdnnSeverity_t level)
// Static accessor implementations for CRTP base class
std::mutex& EnginePluginResourceManager::getMutex()
{
const std::lock_guard<std::mutex> lock(pluginMutex);
if(auto pm = pmPtr.lock())
{
for(const auto& plugin : pm->getPlugins())
{
auto status = plugin->setLogLevel(level);
if(status != HIPDNN_PLUGIN_STATUS_SUCCESS)
{
HIPDNN_BACKEND_LOG_WARN("Failed to set log level for plugin '{}': status {}",
plugin->name(),
static_cast<int>(status));
}
}
}
return gEngineMutex;
}

void EnginePluginResourceManager::setPluginPaths(
const std::vector<std::filesystem::path>& pluginPaths,
hipdnnPluginLoadingMode_ext_t loadingMode)
PluginLoadingConfig& EnginePluginResourceManager::getConfig()
{
const std::lock_guard<std::mutex> lock(pluginMutex);

auto newPathsSet = std::set<std::filesystem::path>{pluginPaths.begin(), pluginPaths.end()};
if(pluginConfig.paths == newPathsSet && pluginConfig.mode == loadingMode)
{
return;
}

// Clear persistent pointer first to allow lazy mode check to work correctly.
// If only persistentPmPtr is keeping plugins alive (no active handles),
// then pmPtr will expire after this reset.
persistentPmPtr.reset();
return gEngineConfig;
}

THROW_IF_FALSE(pmPtr.expired(),
HIPDNN_STATUS_NOT_SUPPORTED,
"hipdnnSetEnginePluginPaths_ext cannot be called with an active handle.");
std::weak_ptr<EnginePluginManager>& EnginePluginResourceManager::getWeakPtr()
{
return gEngineWeakPtr;
}

pluginConfig.mode = loadingMode;
std::shared_ptr<EnginePluginManager>& EnginePluginResourceManager::getPersistentPtr()
{
return gEnginePersistentPtr;
}

if(loadingMode == HIPDNN_PLUGIN_LOADING_ABSOLUTE)
{
pluginConfig.paths = {pluginPaths.begin(), pluginPaths.end()};
}
else
{
pluginConfig.paths.insert(pluginPaths.begin(), pluginPaths.end());
}
std::atomic<bool>& EnginePluginResourceManager::getShutdownFlag()
{
return gEngineShutdownFlag;
}

std::set<std::filesystem::path> EnginePluginResourceManager::getPluginPaths()
const char* EnginePluginResourceManager::getPluginTypeName()
{
const std::lock_guard<std::mutex> lock(pluginMutex);
return pluginConfig.paths;
return "engine";
}

size_t EnginePluginResourceManager::getEngineCount() const
Expand Down Expand Up @@ -155,109 +134,19 @@ std::vector<EngineInfo> EnginePluginResourceManager::getEngineInfos() const
return infos;
}

void EnginePluginResourceManager::setPluginUnloadingMode(hipdnnPluginUnloadingMode_ext_t mode)
{
const std::lock_guard<std::mutex> lock(pluginMutex);

switch(mode)
{
case HIPDNN_PLUGIN_UNLOAD_EAGER:
// Clear persistent pointer - if no handles exist, plugins will be unloaded
persistentPmPtr.reset();
break;

case HIPDNN_PLUGIN_UNLOAD_LAZY:
// If plugins are already loaded, keep them alive by storing in persistent pointer
if(auto pm = pmPtr.lock())
{
persistentPmPtr = pm;
}
// If no plugins loaded yet, persistentPmPtr will be set when create() is called
break;

default:
throw HipdnnException(HIPDNN_STATUS_BAD_PARAM,
"Invalid plugin unloading mode: " + std::to_string(mode));
}

pluginConfig.unloadingMode = mode;
}

void EnginePluginResourceManager::getLoadedPluginFiles(size_t* numPlugins,
char** pluginPaths,
size_t* maxStringLen) const
{
if(!_pm)
{
*numPlugins = 0;
*maxStringLen = 0;
return;
}

const auto& pathSet = _pm->getLoadedPluginFiles();

size_t requiredLen = 0;
for(const auto& path : pathSet)
{
requiredLen = std::max(requiredLen, path.string().length() + 1);
}

if(pluginPaths == nullptr)
{
*numPlugins = pathSet.size();
*maxStringLen = requiredLen;
return;
}

if(*numPlugins < pathSet.size() || *maxStringLen < requiredLen)
{
throw HipdnnException(HIPDNN_STATUS_BAD_PARAM, "Insufficient buffer space provided.");
}

std::vector<std::filesystem::path> pathsVec;
pathsVec.reserve(pathSet.size());
pathsVec.assign(pathSet.begin(), pathSet.end());

for(size_t i = 0; i < pathsVec.size(); ++i)
{
if(pluginPaths[i] == nullptr)
{
throw HipdnnException(HIPDNN_STATUS_BAD_PARAM, "A plugin path string buffer is null.");
}
hipdnn_data_sdk::utilities::copyMaxSizeWithNullTerminator(
pluginPaths[i], pathsVec[i].string().c_str(), *maxStringLen);
}
}

std::shared_ptr<EnginePluginResourceManager> EnginePluginResourceManager::create()
{
const std::lock_guard<std::mutex> lock(pluginMutex);

auto pm = pmPtr.lock();

if(!pm)
{
pm = std::make_shared<EnginePluginManager>();
pm->loadPlugins(pluginConfig.paths, pluginConfig.mode);
pmPtr = pm;

// In lazy mode, keep the plugin manager alive by storing in persistent pointer
if(pluginConfig.unloadingMode == HIPDNN_PLUGIN_UNLOAD_LAZY)
{
persistentPmPtr = pm;
}
}

auto pm = getOrCreatePluginManager();
return std::make_shared<EnginePluginResourceManager>(pm);
}

EnginePluginResourceManager::EnginePluginResourceManager()
: _pm(std::make_shared<EnginePluginManager>())
: PluginResourceManagerBase(std::make_shared<EnginePluginManager>())
{
}

EnginePluginResourceManager::EnginePluginResourceManager(std::shared_ptr<EnginePluginManager> pm)
: _pm(std::move(pm))
: PluginResourceManagerBase(std::move(pm))
{
// Helper to safely destroy a handle during error cleanup, logging any failures
auto safeDestroyHandle = [](const EnginePlugin* plugin, hipdnnEnginePluginHandle_t handle) {
Expand Down Expand Up @@ -338,38 +227,52 @@ EnginePluginResourceManager::EnginePluginResourceManager(std::shared_ptr<EngineP

EnginePluginResourceManager::~EnginePluginResourceManager()
{
// Destroy plugin handles
for(const auto& [handle, plugin] : _handleToPlugin)
{
// Lambda to safely destroy a handle, catching all errors
auto safeDestroyHandle = [](const EnginePlugin* plugin, hipdnnEnginePluginHandle_t handle) {
try
{
plugin->destroyHandle(handle);
}
catch(const HipdnnException& e)
catch(const std::exception& e)
{
HIPDNN_BACKEND_LOG_WARN("Failed to destroy handle for plugin '{}' during cleanup: {}",
plugin->name(),
e.what());
}
catch(...)
{
HIPDNN_BACKEND_LOG_ERROR(e.getMessage());
HIPDNN_BACKEND_LOG_WARN(
"Failed to destroy handle for plugin '{}' during cleanup: unknown error",
plugin->name());
}
};

// Destroy plugin handles
for(const auto& [handle, plugin] : _handleToPlugin)
{
safeDestroyHandle(plugin, handle);
}
}

EnginePluginResourceManager::EnginePluginResourceManager(
EnginePluginResourceManager&& other) noexcept
: _pm(std::move(other._pm))
, _handleToPlugin(std::move(other._handleToPlugin))
: _handleToPlugin(std::move(other._handleToPlugin))
, _engineIdToHandle(std::move(other._engineIdToHandle))
, _cachedEngineInfos(std::move(other._cachedEngineInfos))
{
// Move base class member explicitly
_pm = std::move(other._pm);
}

EnginePluginResourceManager&
EnginePluginResourceManager::operator=(EnginePluginResourceManager&& other) noexcept
{
if(this != &other)
{
_pm = std::move(other._pm);
_handleToPlugin = std::move(other._handleToPlugin);
_engineIdToHandle = std::move(other._engineIdToHandle);
_cachedEngineInfos = std::move(other._cachedEngineInfos);
_pm = std::move(other._pm);
}
return *this;
}
Expand Down
Loading
Loading