Skip to content

Commit 118dc82

Browse files
s-kanaevromanovvlad
authored andcommitted
[SYCL] Intoduce thread-safety for kernels and programs cache (#866)
Signed-off-by: Sergey Kanaev <[email protected]>
1 parent 02c426c commit 118dc82

File tree

8 files changed

+474
-145
lines changed

8 files changed

+474
-145
lines changed

sycl/include/CL/sycl/detail/context_impl.hpp

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#pragma once
1010
#include <CL/sycl/detail/common.hpp>
1111
#include <CL/sycl/detail/device_impl.hpp>
12+
#include <CL/sycl/detail/kernel_program_cache.hpp>
1213
#include <CL/sycl/detail/os_util.hpp>
1314
#include <CL/sycl/detail/pi.hpp>
1415
#include <CL/sycl/detail/platform_impl.hpp>
@@ -110,21 +111,6 @@ class context_impl {
110111
return MDevices;
111112
}
112113

113-
/// Gets cached programs.
114-
///
115-
/// @return a map of cached programs.
116-
std::map<KernelSetId, RT::PiProgram> &getCachedPrograms() {
117-
return MCachedPrograms;
118-
}
119-
120-
/// Gets cached kernels.
121-
///
122-
/// @return a map of cached kernels.
123-
std::map<RT::PiProgram, std::map<string_class, RT::PiKernel>> &
124-
getCachedKernels() {
125-
return MCachedKernels;
126-
}
127-
128114
/// Gets USM dispatcher.
129115
///
130116
/// @return a pointer to USM dispatcher.
@@ -146,17 +132,18 @@ class context_impl {
146132
return MCachedLibPrograms;
147133
}
148134

135+
KernelProgramCache &getKernelProgramCache() const;
136+
149137
private:
150138
async_handler MAsyncHandler;
151139
vector_class<device> MDevices;
152140
RT::PiContext MContext;
153141
PlatformImplPtr MPlatform;
154142
bool MPluginInterop;
155143
bool MHostContext;
156-
std::map<KernelSetId, RT::PiProgram> MCachedPrograms;
157-
std::map<RT::PiProgram, std::map<string_class, RT::PiKernel>> MCachedKernels;
158144
std::shared_ptr<usm::USMDispatcher> MUSMDispatch;
159145
std::map<DeviceLibExt, RT::PiProgram> MCachedLibPrograms;
146+
mutable KernelProgramCache MKernelProgramCache;
160147
};
161148

162149
} // namespace detail
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//==--- kernel_program_cache.hpp - Cache for kernel and program -*- C++-*---==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#pragma once
10+
11+
#include <CL/sycl/detail/locked.hpp>
12+
#include <CL/sycl/detail/os_util.hpp>
13+
#include <CL/sycl/detail/pi.hpp>
14+
15+
#include <atomic>
16+
#include <condition_variable>
17+
#include <map>
18+
#include <mutex>
19+
#include <type_traits>
20+
21+
namespace cl {
22+
namespace sycl {
23+
namespace detail {
24+
class KernelProgramCache {
25+
public:
26+
/// Denotes pointer to some entity with its state.
27+
/// The pointer is not null if and only if the entity is usable.
28+
/// State of the entity is provided by the user of cache instance.
29+
/// Currently there is only a single user - ProgramManager class.
30+
template<typename T>
31+
struct EntityWithState {
32+
std::atomic<T *> Ptr;
33+
std::atomic<int> State;
34+
35+
EntityWithState(T* P, int S)
36+
: Ptr{P}, State{S}
37+
{}
38+
};
39+
40+
using PiProgramT = std::remove_pointer<RT::PiProgram>::type;
41+
using PiProgramPtrT = std::atomic<PiProgramT *>;
42+
using ProgramWithBuildStateT = EntityWithState<PiProgramT>;
43+
using ProgramCacheT = std::map<OSModuleHandle, ProgramWithBuildStateT>;
44+
45+
using PiKernelT = std::remove_pointer<RT::PiKernel>::type;
46+
using PiKernelPtrT = std::atomic<PiKernelT *>;
47+
using KernelWithBuildStateT = EntityWithState<PiKernelT>;
48+
using KernelByNameT = std::map<string_class, KernelWithBuildStateT>;
49+
using KernelCacheT = std::map<RT::PiProgram, KernelByNameT>;
50+
51+
~KernelProgramCache();
52+
53+
Locked<ProgramCacheT> acquireCachedPrograms() {
54+
return {MCachedPrograms, MProgramCacheMutex};
55+
}
56+
57+
Locked<KernelCacheT> acquireKernelsPerProgramCache() {
58+
return {MKernelsPerProgramCache, MKernelsPerProgramCacheMutex};
59+
}
60+
61+
template<class Predicate>
62+
void waitUntilBuilt(Predicate Pred) const {
63+
std::unique_lock<std::mutex> Lock(MBuildCVMutex);
64+
65+
MBuildCV.wait(Lock, Pred);
66+
}
67+
68+
void notifyAllBuild() const {
69+
MBuildCV.notify_all();
70+
}
71+
72+
private:
73+
std::mutex MProgramCacheMutex;
74+
std::mutex MKernelsPerProgramCacheMutex;
75+
76+
mutable std::condition_variable MBuildCV;
77+
mutable std::mutex MBuildCVMutex;
78+
79+
ProgramCacheT MCachedPrograms;
80+
KernelCacheT MKernelsPerProgramCache;
81+
};
82+
}
83+
}
84+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//==---------------- locked.hpp - Reference with lock -----------*- C++-*---==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#pragma once
10+
11+
#include <functional>
12+
#include <mutex>
13+
14+
namespace cl {
15+
namespace sycl {
16+
namespace detail {
17+
/// Represents a reference to value with appropriate lock acquired.
18+
/// Employed for acquire/release logic. Acquire action is construction
19+
/// of instance of locked<>. Release action is destruction of instance of
20+
/// locked<>.
21+
template <typename T>
22+
class Locked {
23+
std::reference_wrapper<T> m_Value;
24+
std::unique_lock<std::mutex> m_Lock;
25+
26+
public:
27+
Locked(T &v, std::mutex &mutex)
28+
: m_Value{v}, m_Lock{mutex}
29+
{}
30+
31+
T& get() const {
32+
return m_Value.get();
33+
}
34+
};
35+
}
36+
}
37+
}

sycl/source/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ set(SYCL_SOURCES
6161
"detail/image_impl.cpp"
6262
"detail/kernel_impl.cpp"
6363
"detail/kernel_info.cpp"
64+
"detail/kernel_program_cache.cpp"
6465
"detail/memory_manager.cpp"
6566
"detail/platform_impl.cpp"
6667
"detail/platform_info.cpp"

sycl/source/detail/context_impl.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,6 @@ context_impl::~context_impl() {
8383
// TODO catch an exception and put it to list of asynchronous exceptions
8484
PI_CALL(piContextRelease)(MContext);
8585
}
86-
// Release all programs and kernels created with this context
87-
for (auto ProgIt : MCachedPrograms) {
88-
RT::PiProgram ToBeDeleted = ProgIt.second;
89-
for (auto KernIt : MCachedKernels[ToBeDeleted])
90-
PI_CALL(piKernelRelease)(KernIt.second);
91-
PI_CALL(piProgramRelease)(ToBeDeleted);
92-
}
9386
for (auto LibProg : MCachedLibPrograms) {
9487
assert(LibProg.second && "Null program must not be kept in the cache");
9588
PI_CALL(piProgramRelease)(LibProg.second);
@@ -123,6 +116,10 @@ std::shared_ptr<usm::USMDispatcher> context_impl::getUSMDispatch() const {
123116
return MUSMDispatch;
124117
}
125118

119+
KernelProgramCache &context_impl::getKernelProgramCache() const {
120+
return MKernelProgramCache;
121+
}
122+
126123
} // namespace detail
127124
} // namespace sycl
128125
} // namespace cl
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//==--- kernel_program_cache.cpp - Cache for kernel and program -*- C++-*---==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <CL/sycl/detail/kernel_program_cache.hpp>
10+
11+
namespace cl {
12+
namespace sycl {
13+
namespace detail {
14+
KernelProgramCache::~KernelProgramCache() {
15+
for (auto &ProgIt : MCachedPrograms) {
16+
ProgramWithBuildStateT &ProgWithState = ProgIt.second;
17+
PiProgramT *ToBeDeleted = ProgWithState.Ptr.load();
18+
19+
if (!ToBeDeleted)
20+
continue;
21+
22+
auto KernIt = MKernelsPerProgramCache.find(ToBeDeleted);
23+
24+
if (KernIt == MKernelsPerProgramCache.end())
25+
continue;
26+
27+
for (auto &p : KernIt->second) {
28+
KernelWithBuildStateT &KernelWithState = p.second;
29+
PiKernelT *Kern = KernelWithState.Ptr.load();
30+
31+
if (Kern)
32+
PI_CALL(piKernelRelease)(Kern);
33+
}
34+
35+
PI_CALL(piProgramRelease)(ToBeDeleted);
36+
}
37+
}
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)