Skip to content

[SYCL] Complete transition to Managed<ur_program_handle_t> RAII model #19557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Jul 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
993aed3
program_manager.cpp: static create*
aelovikov-intel Jul 21, 2025
e18c0c1
ProgramManager::createURProgram
aelovikov-intel Jul 21, 2025
5d209d3
program_manager.cpp: loadDeviceLib
aelovikov-intel Jul 21, 2025
11ffadc
ProgramManager::getOrCreateURProgram
aelovikov-intel Jul 21, 2025
0ea85a3
BuildF lambda, hopefully...
aelovikov-intel Jul 21, 2025
7d7531a
FastKernelCacheVal ctor
aelovikov-intel Jul 21, 2025
6e3345d
extKernelCompilerFetchFromCache
aelovikov-intel Jul 21, 2025
9962068
createProgramFromSource
aelovikov-intel Jul 21, 2025
e9feebf
device_image_impl ctor overload 0
aelovikov-intel Jul 21, 2025
af403f0
device_image_impl ctor overload 1
aelovikov-intel Jul 21, 2025
dd34ba5
Drop unused device_image_impl ctor overload 2
aelovikov-intel Jul 21, 2025
da04557
Last affected device_image_impl ctor overload
aelovikov-intel Jul 21, 2025
5c57574
Move up
aelovikov-intel Jul 21, 2025
1799d4f
Debug prints
aelovikov-intel Jul 21, 2025
fe03fa8
"Outer" getBuiltURProgram overload
aelovikov-intel Jul 21, 2025
e2dbbcc
Remaining ProgramManager::getBuiltURProgram overload
aelovikov-intel Jul 21, 2025
c97ec87
backend.cpp
aelovikov-intel Jul 22, 2025
854a46a
ProgramBuildResult ctor simplification
aelovikov-intel Jul 22, 2025
7432a51
debug print old
aelovikov-intel Jul 22, 2025
f0229bf
Proper retain in insertBuiltProgram
aelovikov-intel Jul 22, 2025
944ac98
One more retain
aelovikov-intel Jul 22, 2025
11e0a36
Remove unused `Adapter` after managed retains
aelovikov-intel Jul 22, 2025
f5221d9
loadDeviceLibFallback (last retain)
aelovikov-intel Jul 22, 2025
4f06a1a
Drop debug printing
aelovikov-intel Jul 22, 2025
f59f3c6
clang-format
aelovikov-intel Jul 22, 2025
28d0048
rvalue-ref in device_image_impl ctor
aelovikov-intel Jul 22, 2025
5208f86
Remove stale comment
aelovikov-intel Jul 22, 2025
49dc0ba
Fix for the failing e2e test
aelovikov-intel Jul 23, 2025
fff3362
Remove stale comment - context_impl owns these
aelovikov-intel Jul 23, 2025
ebf3ce1
Fix one leak
aelovikov-intel Jul 23, 2025
134bf45
Merge remote-tracking branch 'origin/sycl' into HEAD
aelovikov-intel Jul 23, 2025
8fcca38
Update test
aelovikov-intel Jul 23, 2025
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
17 changes: 9 additions & 8 deletions sycl/source/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ make_kernel_bundle(ur_native_handle_t NativeHandle,
adapter_impl &Adapter = getAdapter(Backend);
context_impl &ContextImpl = *getSyclObjImpl(TargetContext);

ur_program_handle_t UrProgram = nullptr;
Managed<ur_program_handle_t> UrProgram{Adapter};
ur_program_native_properties_t Properties{};
Properties.stype = UR_STRUCTURE_TYPE_PROGRAM_NATIVE_PROPERTIES;
Properties.isNativeHandleOwned = !KeepOwnership;
Expand Down Expand Up @@ -258,18 +258,19 @@ make_kernel_bundle(ur_native_handle_t NativeHandle,
"Program and kernel_bundle state mismatch " +
detail::codeToString(UR_RESULT_ERROR_INVALID_VALUE));
if (State == bundle_state::executable) {
ur_program_handle_t UrLinkedProgram = nullptr;
Managed<ur_program_handle_t> UrLinkedProgram{Adapter};
ur_program_handle_t ProgramsToLink[] = {UrProgram};
auto Res = Adapter.call_nocheck<UrApiKind::urProgramLinkExp>(
ContextImpl.getHandleRef(), 1u, &Dev, 1u, &UrProgram, nullptr,
ContextImpl.getHandleRef(), 1u, &Dev, 1u, ProgramsToLink, nullptr,
&UrLinkedProgram);
if (Res == UR_RESULT_ERROR_UNSUPPORTED_FEATURE) {
Res = Adapter.call_nocheck<UrApiKind::urProgramLink>(
ContextImpl.getHandleRef(), 1u, &UrProgram, nullptr,
ContextImpl.getHandleRef(), 1u, ProgramsToLink, nullptr,
&UrLinkedProgram);
}
Adapter.checkUrResult<errc::build>(Res);
if (UrLinkedProgram != nullptr) {
UrProgram = UrLinkedProgram;
UrProgram = std::move(UrLinkedProgram);
}
}
break;
Expand Down Expand Up @@ -301,9 +302,9 @@ make_kernel_bundle(ur_native_handle_t NativeHandle,
// do the same to user images, since they may contain references to undefined
// symbols (e.g. when kernel_bundle is supposed to be joined with another).
auto KernelIDs = std::make_shared<std::vector<kernel_id>>();
auto DevImgImpl =
device_image_impl::create(nullptr, TargetContext, Devices, State,
KernelIDs, UrProgram, ImageOriginInterop);
auto DevImgImpl = device_image_impl::create(
nullptr, TargetContext, Devices, State, KernelIDs, std::move(UrProgram),
ImageOriginInterop);
device_image_plain DevImg{DevImgImpl};

return kernel_bundle_impl::create(TargetContext, Devices, DevImg);
Expand Down
17 changes: 17 additions & 0 deletions sycl/source/detail/adapter_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ template <typename URResource> class Managed {
if constexpr (std::is_same_v<URResource, ur_program_handle_t>)
return UrApiKind::urProgramRelease;
}();
static constexpr auto Retain = []() constexpr {
if constexpr (std::is_same_v<URResource, ur_program_handle_t>)
return UrApiKind::urProgramRetain;
}();

public:
Managed() = default;
Expand All @@ -258,6 +262,7 @@ template <typename URResource> class Managed {
Managed &operator=(Managed &&Other) {
if (R)
Adapter->call<Release>(R);

R = Other.R;
Other.R = nullptr;
Adapter = Other.Adapter;
Expand Down Expand Up @@ -285,6 +290,18 @@ template <typename URResource> class Managed {
Adapter->call<Release>(R);
}

Managed retain() {
assert(R && "Cannot retain unintialized resource!");
Adapter->call<Retain>(R);
return Managed{R, *Adapter};
}

bool operator==(const Managed &Other) const {
assert((!Adapter || !Other.Adapter || Adapter == Other.Adapter) &&
"Objects must belong to the same adapter!");
return R == Other.R;
}

private:
URResource R = nullptr;
adapter_impl *Adapter = nullptr;
Expand Down
58 changes: 20 additions & 38 deletions sycl/source/detail/device_image_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,11 @@ class device_image_impl
device_image_impl(const RTDeviceBinaryImage *BinImage, context Context,
devices_range Devices, bundle_state State,
std::shared_ptr<std::vector<kernel_id>> KernelIDs,
ur_program_handle_t Program, uint8_t Origins, private_tag)
Managed<ur_program_handle_t> &&Program, uint8_t Origins,
private_tag)
: MBinImage(BinImage), MContext(std::move(Context)),
MDevices(Devices.to<std::vector<device_impl *>>()), MState(State),
MProgram(Program, getSyclObjImpl(MContext)->getAdapter()),
MKernelIDs(std::move(KernelIDs)),
MProgram(std::move(Program)), MKernelIDs(std::move(KernelIDs)),
MSpecConstsDefValBlob(getSpecConstsDefValBlob()), MOrigins(Origins) {
updateSpecConstSymMap();
if (BinImage && (MOrigins & ImageOriginSYCLBIN)) {
Expand All @@ -287,40 +287,23 @@ class device_image_impl
const RTDeviceBinaryImage *BinImage, const context &Context,
devices_range Devices, bundle_state State,
std::shared_ptr<std::vector<kernel_id>> KernelIDs,
ur_program_handle_t Program, const SpecConstMapT &SpecConstMap,
Managed<ur_program_handle_t> &&Program, const SpecConstMapT &SpecConstMap,
const std::vector<unsigned char> &SpecConstsBlob, uint8_t Origins,
std::optional<KernelCompilerBinaryInfo> &&RTCInfo,
KernelNameSetT &&KernelNames,
KernelNameToArgMaskMap &&EliminatedKernelArgMasks,
std::unique_ptr<DynRTDeviceBinaryImage> &&MergedImageStorage, private_tag)
: MBinImage(BinImage), MContext(std::move(Context)),
MDevices(Devices.to<std::vector<device_impl *>>()), MState(State),
MProgram(Program, getSyclObjImpl(MContext)->getAdapter()),
MKernelIDs(std::move(KernelIDs)), MKernelNames{std::move(KernelNames)},
MProgram(std::move(Program)), MKernelIDs(std::move(KernelIDs)),
MKernelNames{std::move(KernelNames)},
MEliminatedKernelArgMasks{std::move(EliminatedKernelArgMasks)},
MSpecConstsBlob(SpecConstsBlob),
MSpecConstsDefValBlob(getSpecConstsDefValBlob()),
MSpecConstSymMap(SpecConstMap), MOrigins(Origins),
MRTCBinInfo(std::move(RTCInfo)),
MMergedImageStorage(std::move(MergedImageStorage)) {}

device_image_impl(const RTDeviceBinaryImage *BinImage, const context &Context,
devices_range Devices, bundle_state State,
ur_program_handle_t Program, syclex::source_language Lang,
KernelNameSetT &&KernelNames,
KernelNameToArgMaskMap &&EliminatedKernelArgMasks,
private_tag)
: MBinImage(BinImage), MContext(std::move(Context)),
MDevices(Devices.to<std::vector<device_impl *>>()), MState(State),
MProgram(Program, getSyclObjImpl(MContext)->getAdapter()),
MKernelNames{std::move(KernelNames)},
MEliminatedKernelArgMasks{std::move(EliminatedKernelArgMasks)},
MSpecConstsDefValBlob(getSpecConstsDefValBlob()),
MOrigins(ImageOriginKernelCompiler),
MRTCBinInfo(KernelCompilerBinaryInfo{Lang}) {
updateSpecConstSymMap();
}

device_image_impl(
const RTDeviceBinaryImage *BinImage, const context &Context,
devices_range Devices, bundle_state State,
Expand Down Expand Up @@ -366,14 +349,13 @@ class device_image_impl
}

device_image_impl(const context &Context, devices_range Devices,
bundle_state State, ur_program_handle_t Program,
bundle_state State, Managed<ur_program_handle_t> &&Program,
syclex::source_language Lang, KernelNameSetT &&KernelNames,
private_tag)
: MBinImage(static_cast<const RTDeviceBinaryImage *>(nullptr)),
MContext(std::move(Context)),
MDevices(Devices.to<std::vector<device_impl *>>()), MState(State),
MProgram(Program, getSyclObjImpl(MContext)->getAdapter()),
MKernelNames{std::move(KernelNames)},
MProgram(std::move(Program)), MKernelNames{std::move(KernelNames)},
MSpecConstsDefValBlob(getSpecConstsDefValBlob()),
MOrigins(ImageOriginKernelCompiler),
MRTCBinInfo(KernelCompilerBinaryInfo{Lang}) {}
Expand Down Expand Up @@ -771,14 +753,14 @@ class device_image_impl

auto DeviceVec = Devices.to<std::vector<ur_device_handle_t>>();

ur_program_handle_t UrProgram = nullptr;
Managed<ur_program_handle_t> UrProgram;
// SourceStrPtr will be null when source is Spir-V bytes.
const std::string *SourceStrPtr = std::get_if<std::string>(&MBinImage);
bool FetchedFromCache = false;
if (PersistentDeviceCodeCache::isEnabled() && SourceStrPtr) {
FetchedFromCache = extKernelCompilerFetchFromCache(
Devices, BuildOptions, *SourceStrPtr, UrProgram);
UrProgram =
extKernelCompilerFetchFromCache(Devices, BuildOptions, *SourceStrPtr);
}
bool FetchedFromCache = (UrProgram != nullptr);

adapter_impl &Adapter = ContextImpl.getAdapter();

Expand Down Expand Up @@ -813,7 +795,7 @@ class device_image_impl
}
return std::vector<std::shared_ptr<device_image_impl>>{
device_image_impl::create(MContext, Devices, bundle_state::executable,
UrProgram, MRTCBinInfo->MLanguage,
std::move(UrProgram), MRTCBinInfo->MLanguage,
std::move(KernelNameSet))};
}

Expand Down Expand Up @@ -907,10 +889,10 @@ class device_image_impl
return SS.str();
}

bool extKernelCompilerFetchFromCache(
Managed<ur_program_handle_t> extKernelCompilerFetchFromCache(
devices_range Devices,
const std::vector<sycl::detail::string_view> &BuildOptions,
const std::string &SourceStr, ur_program_handle_t &UrProgram) const {
const std::string &SourceStr) const {
sycl::detail::context_impl &ContextImpl = *getSyclObjImpl(MContext);
adapter_impl &Adapter = ContextImpl.getAdapter();

Expand All @@ -924,7 +906,7 @@ class device_image_impl
PersistentDeviceCodeCache::getCompiledKernelFromDisc(Devices, UserArgs,
SourceStr);
if (BinProgs.empty()) {
return false;
return {};
}
for (auto &BinProg : BinProgs) {
Binaries.push_back((uint8_t *)(BinProg.data()));
Expand All @@ -937,11 +919,12 @@ class device_image_impl
Properties.count = 0;
Properties.pMetadatas = nullptr;

Managed<ur_program_handle_t> UrProgram{Adapter};
Adapter.call<UrApiKind::urProgramCreateWithBinary>(
ContextImpl.getHandleRef(), DeviceHandles.size(), DeviceHandles.data(),
Lengths.data(), Binaries.data(), &Properties, &UrProgram);

return true;
return UrProgram;
}

// Get the specialization constant default value blob.
Expand Down Expand Up @@ -1226,7 +1209,7 @@ class device_image_impl
return Result;
}

ur_program_handle_t
Managed<ur_program_handle_t>
createProgramFromSource(devices_range Devices,
const std::vector<sycl::detail::string_view> &Options,
std::string *LogPtr) const {
Expand Down Expand Up @@ -1266,11 +1249,10 @@ class device_image_impl
"languages at this time");
}();

ur_program_handle_t UrProgram = nullptr;
Managed<ur_program_handle_t> UrProgram{Adapter};
Adapter.call<UrApiKind::urProgramCreateWithIL>(ContextImpl.getHandleRef(),
spirv.data(), spirv.size(),
nullptr, &UrProgram);
// program created by urProgramCreateWithIL is implicitly retained.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know what that comment tried to communicate...

if (UrProgram == nullptr)
throw sycl::exception(
sycl::make_error_code(errc::invalid),
Expand Down
3 changes: 2 additions & 1 deletion sycl/source/detail/kernel_bundle_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,8 @@ class kernel_bundle_impl
for (const detail::RTDeviceBinaryImage *Image : BestImages)
MDeviceImages.emplace_back(device_image_impl::create(
Image, Context, Devs, ProgramManager::getBinImageState(Image),
/*KernelIDs=*/nullptr, /*URProgram=*/nullptr, ImageOriginSYCLBIN));
/*KernelIDs=*/nullptr, Managed<ur_program_handle_t>{},
ImageOriginSYCLBIN));
ProgramManager::getInstance().bringSYCLDeviceImagesToState(MDeviceImages,
State);
fillUniqueDeviceImages();
Expand Down
5 changes: 3 additions & 2 deletions sycl/source/detail/kernel_name_based_cache_t.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ struct FastKernelCacheVal {

FastKernelCacheVal(ur_kernel_handle_t KernelHandle, std::mutex *Mutex,
const KernelArgMask *KernelArgMask,
ur_program_handle_t ProgramHandle, adapter_impl &Adapter)
Managed<ur_program_handle_t> &&ProgramHandle,
adapter_impl &Adapter)
: MKernelHandle(KernelHandle), MMutex(Mutex),
MKernelArgMask(KernelArgMask), MProgramHandle(ProgramHandle, Adapter),
MKernelArgMask(KernelArgMask), MProgramHandle(std::move(ProgramHandle)),
MAdapter(Adapter) {}

~FastKernelCacheVal() {
Expand Down
28 changes: 13 additions & 15 deletions sycl/source/detail/kernel_program_cache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,11 @@ class KernelProgramCache {
};

struct ProgramBuildResult : public BuildResult<Managed<ur_program_handle_t>> {
ProgramBuildResult(adapter_impl &Adapter) {
Val = Managed<ur_program_handle_t>{Adapter};
}
ProgramBuildResult(adapter_impl &Adapter, BuildState InitialState) {
Val = Managed<ur_program_handle_t>{Adapter};
ProgramBuildResult() = default;
ProgramBuildResult(BuildState InitialState,
Managed<ur_program_handle_t> &&Prog) {
this->State.store(InitialState);
this->Val = std::move(Prog);
}
#ifdef _MSC_VER
#pragma warning(push)
Expand Down Expand Up @@ -407,7 +406,7 @@ class KernelProgramCache {
ProgramCache &ProgCache = LockedCache.get();
auto [It, DidInsert] = ProgCache.Cache.try_emplace(CacheKey, nullptr);
if (DidInsert) {
It->second = std::make_shared<ProgramBuildResult>(getAdapter());
It->second = std::make_shared<ProgramBuildResult>();
// Save reference between the common key and the full key.
CommonProgramKeyT CommonKey =
std::make_pair(CacheKey.first.second, CacheKey.second);
Expand All @@ -424,14 +423,13 @@ class KernelProgramCache {
//
// Returns whether or not an insertion took place.
bool insertBuiltProgram(const ProgramCacheKeyT &CacheKey,
ur_program_handle_t Program) {
Managed<ur_program_handle_t> &Program) {
auto LockedCache = acquireCachedPrograms();
ProgramCache &ProgCache = LockedCache.get();
auto [It, DidInsert] = ProgCache.Cache.try_emplace(CacheKey, nullptr);
if (DidInsert) {
It->second = std::make_shared<ProgramBuildResult>(getAdapter(),
BuildState::BS_Done);
It->second->Val = Managed<ur_program_handle_t>{Program, getAdapter()};
It->second = std::make_shared<ProgramBuildResult>(BuildState::BS_Done,
Program.retain());
// Save reference between the common key and the full key.
CommonProgramKeyT CommonKey =
std::make_pair(CacheKey.first.second, CacheKey.second);
Expand Down Expand Up @@ -643,8 +641,7 @@ class KernelProgramCache {
// If it is the first time the program is fetched, add it to the eviction
// list.
void registerProgramFetch(const ProgramCacheKeyT &CacheKey,
const ur_program_handle_t &Program,
const bool IsBuilt) {
ur_program_handle_t Program, const bool IsBuilt) {

size_t ProgramCacheEvictionThreshold =
SYCLConfig<SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD>::getProgramCacheSize();
Expand Down Expand Up @@ -799,9 +796,10 @@ class KernelProgramCache {

// only the building thread will run this
try {
// Remove `adapter_impl` from `ProgramBuildResult`'s ctors once `Build`
// returns `Managed<ur_platform_handle_t`:
*(&BuildResult->Val) = Build();
static_assert(
std::is_same_v<decltype(Build()), decltype(BuildResult->Val)>,
"Are we casting from Managed<URResource> to plain URResource?");
BuildResult->Val = Build();

if constexpr (!std::is_same_v<EvictFT, void *>)
EvictFunc(BuildResult->Val, /*IsBuilt=*/true);
Expand Down
Loading