Skip to content

[NFC][SYCL] Add devices_range helper to cleanup persistent_device_code_cache #19405

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 1 commit into from
Jul 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions sycl/source/detail/device_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#pragma once

#include <detail/helpers.hpp>
#include <detail/platform_impl.hpp>
#include <detail/program_manager/program_manager.hpp>
#include <sycl/aspects.hpp>
Expand Down Expand Up @@ -2281,6 +2282,33 @@ class device_impl : public std::enable_shared_from_this<device_impl> {

}; // class device_impl

struct devices_deref_impl {
template <typename T> static device_impl &dereference(T &Elem) {
using Ty = std::decay_t<decltype(Elem)>;
if constexpr (std::is_same_v<Ty, device>) {
return *getSyclObjImpl(Elem);
} else if constexpr (std::is_same_v<Ty, device_impl>) {
return Elem;
} else {
return *Elem;
}
}
};
using devices_iterator =
variadic_iterator<devices_deref_impl,
std::vector<std::shared_ptr<device_impl>>::const_iterator,
std::vector<device>::const_iterator, device_impl *>;

class devices_range : public iterator_range<devices_iterator> {
private:
using Base = iterator_range<devices_iterator>;

public:
using Base::Base;
devices_range(const device &Dev)
: devices_range(&*getSyclObjImpl(Dev), (&*getSyclObjImpl(Dev) + 1), 1) {}
};

#ifndef __INTEL_PREVIEW_BREAKING_CHANGES
template <typename Param>
typename Param::return_type device_impl::get_info() const {
Expand Down
112 changes: 37 additions & 75 deletions sycl/source/detail/graph/node_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

#include <detail/accessor_impl.hpp> // for AccessorImplHost
#include <detail/cg.hpp> // for CGExecKernel, CGHostTask, ArgDesc...
#include <detail/host_task.hpp> // for HostTask
#include <sycl/detail/cg_types.hpp> // for CGType
#include <detail/helpers.hpp>
#include <detail/host_task.hpp> // for HostTask
#include <sycl/detail/cg_types.hpp> // for CGType
#include <sycl/detail/kernel_desc.hpp> // for kernel_param_kind_t

#include <cstring>
Expand Down Expand Up @@ -761,82 +762,43 @@ class node_impl : public std::enable_shared_from_this<node_impl> {
}
};

// Non-owning!
class nodes_range {
template <typename... Containers>
using storage_iter_impl =
std::variant<typename Containers::const_iterator...>;

using storage_iter = storage_iter_impl<
std::vector<std::shared_ptr<node_impl>>, std::vector<node_impl *>,
// Next one is temporary. It looks like `weak_ptr`s aren't
// used for the actual lifetime management and the objects are
// always guaranteed to be alive. Once the code is cleaned
// from `weak_ptr`s this alternative should be removed too.
std::vector<std::weak_ptr<node_impl>>,
//
std::set<std::shared_ptr<node_impl>>, std::set<node_impl *>,
//
std::list<node_impl *>>;

storage_iter Begin;
storage_iter End;
const size_t Size;

public:
nodes_range(const nodes_range &Other) = default;

template <
typename ContainerTy,
typename = std::enable_if_t<!std::is_same_v<nodes_range, ContainerTy>>>
nodes_range(ContainerTy &Container)
: Begin{Container.begin()}, End{Container.end()}, Size{Container.size()} {
struct nodes_deref_impl {
template <typename T> static node_impl &dereference(T &Elem) {
if constexpr (std::is_same_v<std::decay_t<decltype(Elem)>,
std::weak_ptr<node_impl>>) {
// This assumes that weak_ptr doesn't actually manage lifetime and
// the object is guaranteed to be alive (which seems to be the
// assumption across all graph code).
return *Elem.lock();
} else {
return *Elem;
}
}
};

class iterator {
storage_iter It;

iterator(storage_iter It) : It(It) {}
friend class nodes_range;

public:
iterator &operator++() {
It = std::visit(
[](auto &&It) {
++It;
return storage_iter{It};
},
It);
return *this;
}
bool operator!=(const iterator &Other) const { return It != Other.It; }

node_impl &operator*() {
return std::visit(
[](auto &&It) -> node_impl & {
auto &Elem = *It;
if constexpr (std::is_same_v<std::decay_t<decltype(Elem)>,
std::weak_ptr<node_impl>>) {
// This assumes that weak_ptr doesn't actually manage lifetime and
// the object is guaranteed to be alive (which seems to be the
// assumption across all graph code).
return *Elem.lock();
} else {
return *Elem;
}
},
It);
}
};
template <typename... ContainerTy>
using nodes_iterator_impl =
variadic_iterator<nodes_deref_impl,
typename ContainerTy::const_iterator...>;

using nodes_iterator = nodes_iterator_impl<
std::vector<std::shared_ptr<node_impl>>, std::vector<node_impl *>,
// Next one is temporary. It looks like `weak_ptr`s aren't
// used for the actual lifetime management and the objects are
// always guaranteed to be alive. Once the code is cleaned
// from `weak_ptr`s this alternative should be removed too.
std::vector<std::weak_ptr<node_impl>>,
//
std::set<std::shared_ptr<node_impl>>, std::set<node_impl *>,
//
std::list<node_impl *>>;

class nodes_range : public iterator_range<nodes_iterator> {
private:
using Base = iterator_range<nodes_iterator>;

iterator begin() const {
return {std::visit([](auto &&It) { return storage_iter{It}; }, Begin)};
}
iterator end() const {
return {std::visit([](auto &&It) { return storage_iter{It}; }, End)};
}
size_t size() const { return Size; }
bool empty() const { return Size == 0; }
public:
using Base::Base;
};

inline nodes_range node_impl::successors() const { return MSuccessors; }
Expand Down
60 changes: 60 additions & 0 deletions sycl/source/detail/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
//
//===----------------------------------------------------------------------===//

#pragma once

#include <sycl/detail/kernel_name_str_t.hpp>

#include <ur_api.h>

#include <memory>
#include <tuple>
#include <variant>
#include <vector>

namespace sycl {
Expand All @@ -26,6 +29,63 @@ class RTDeviceBinaryImage;
std::tuple<const RTDeviceBinaryImage *, ur_program_handle_t>
retrieveKernelBinary(queue_impl &Queue, KernelNameStrRefT KernelName,
CGExecKernel *CGKernel = nullptr);

template <typename DereferenceImpl, typename... Iterators>
class variadic_iterator {
using storage_iter = std::variant<Iterators...>;

storage_iter It;

public:
template <typename IterTy>
variadic_iterator(IterTy &&It) : It(std::forward<IterTy>(It)) {}

variadic_iterator &operator++() {
It = std::visit(
[](auto &&It) {
++It;
return storage_iter{It};
},
It);
return *this;
}
bool operator!=(const variadic_iterator &Other) const {
return It != Other.It;
}

decltype(auto) operator*() {
return std::visit(
[](auto &&It) -> decltype(auto) {
return DereferenceImpl::dereference(*It);
},
It);
}
};

// Non-owning!
template <typename iterator> class iterator_range {
public:
iterator_range(const iterator_range &Other) = default;

template <typename IterTy>
iterator_range(IterTy Begin, IterTy End, size_t Size)
: Begin(Begin), End(End), Size(Size) {}

template <typename ContainerTy>
iterator_range(const ContainerTy &Container)
: iterator_range(Container.begin(), Container.end(), Container.size()) {}

iterator begin() const { return Begin; }
iterator end() const { return End; }
size_t size() const { return Size; }
bool empty() const { return Size == 0; }
decltype(auto) front() const { return *begin(); }

private:
iterator Begin;
iterator End;
const size_t Size;
};
} // namespace detail
} // namespace _V1
} // namespace sycl
Loading