Skip to content

Commit 4bf1fe3

Browse files
[SYCL] Initial implementation of dynamic linking support in runtime (#14587)
This patch provides an initial implementation for supporting the dynamic linking feature. Current known limitations are: lack of kernel bundle and AOT support.
1 parent 4240ef0 commit 4bf1fe3

File tree

12 files changed

+659
-289
lines changed

12 files changed

+659
-289
lines changed

sycl/include/sycl/detail/pi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,8 @@ static const uint8_t PI_DEVICE_BINARY_OFFLOAD_KIND_SYCL = 4;
10831083
#define __SYCL_PI_PROPERTY_SET_SYCL_ASSERT_USED "SYCL/assert used"
10841084
/// PropertySetRegistry::SYCL_EXPORTED_SYMBOLS defined in PropertySetIO.h
10851085
#define __SYCL_PI_PROPERTY_SET_SYCL_EXPORTED_SYMBOLS "SYCL/exported symbols"
1086+
/// PropertySetRegistry::SYCL_IMPORTED_SYMBOLS defined in PropertySetIO.h
1087+
#define __SYCL_PI_PROPERTY_SET_SYCL_IMPORTED_SYMBOLS "SYCL/imported symbols"
10861088
/// PropertySetRegistry::SYCL_DEVICE_GLOBALS defined in PropertySetIO.h
10871089
#define __SYCL_PI_PROPERTY_SET_SYCL_DEVICE_GLOBALS "SYCL/device globals"
10881090
/// PropertySetRegistry::SYCL_DEVICE_REQUIREMENTS defined in PropertySetIO.h

sycl/source/detail/device_binary_image.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ void RTDeviceBinaryImage::init(pi_device_binary Bin) {
178178
AssertUsed.init(Bin, __SYCL_PI_PROPERTY_SET_SYCL_ASSERT_USED);
179179
ProgramMetadata.init(Bin, __SYCL_PI_PROPERTY_SET_PROGRAM_METADATA);
180180
ExportedSymbols.init(Bin, __SYCL_PI_PROPERTY_SET_SYCL_EXPORTED_SYMBOLS);
181+
ImportedSymbols.init(Bin, __SYCL_PI_PROPERTY_SET_SYCL_IMPORTED_SYMBOLS);
181182
DeviceGlobals.init(Bin, __SYCL_PI_PROPERTY_SET_SYCL_DEVICE_GLOBALS);
182183
DeviceRequirements.init(Bin, __SYCL_PI_PROPERTY_SET_SYCL_DEVICE_REQUIREMENTS);
183184
HostPipes.init(Bin, __SYCL_PI_PROPERTY_SET_SYCL_HOST_PIPES);

sycl/source/detail/device_binary_image.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ class RTDeviceBinaryImage {
214214
const PropertyRange &getAssertUsed() const { return AssertUsed; }
215215
const PropertyRange &getProgramMetadata() const { return ProgramMetadata; }
216216
const PropertyRange &getExportedSymbols() const { return ExportedSymbols; }
217+
const PropertyRange &getImportedSymbols() const { return ImportedSymbols; }
217218
const PropertyRange &getDeviceGlobals() const { return DeviceGlobals; }
218219
const PropertyRange &getDeviceRequirements() const {
219220
return DeviceRequirements;
@@ -240,6 +241,7 @@ class RTDeviceBinaryImage {
240241
RTDeviceBinaryImage::PropertyRange AssertUsed;
241242
RTDeviceBinaryImage::PropertyRange ProgramMetadata;
242243
RTDeviceBinaryImage::PropertyRange ExportedSymbols;
244+
RTDeviceBinaryImage::PropertyRange ImportedSymbols;
243245
RTDeviceBinaryImage::PropertyRange DeviceGlobals;
244246
RTDeviceBinaryImage::PropertyRange DeviceRequirements;
245247
RTDeviceBinaryImage::PropertyRange HostPipes;

sycl/source/detail/persistent_device_code_cache.cpp

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,19 @@ IsSupportedImageFormat(sycl::detail::pi::PiDeviceBinaryType Format) {
5959
Format == PI_DEVICE_BINARY_TYPE_NATIVE;
6060
}
6161

62-
/* Returns true if specified image should be cached on disk. It checks if
63-
* cache is enabled, image has supported format and matches thresholds. */
64-
bool PersistentDeviceCodeCache::isImageCached(const RTDeviceBinaryImage &Img) {
62+
/* Returns true if specified images should be cached on disk. It checks if
63+
* cache is enabled, images have supported format and match thresholds. */
64+
bool PersistentDeviceCodeCache::areImagesCacheable(
65+
const std::vector<const RTDeviceBinaryImage *> &Imgs) {
66+
assert(!Imgs.empty());
67+
auto Format = Imgs[0]->getFormat();
68+
assert(std::all_of(Imgs.begin(), Imgs.end(),
69+
[&Format](const RTDeviceBinaryImage *Img) {
70+
return Img->getFormat() == Format;
71+
}) &&
72+
"All images are expected to have the same format");
6573
// Cache should be enabled and image type is one of the supported formats.
66-
if (!isEnabled() || !IsSupportedImageFormat(Img.getFormat()))
74+
if (!isEnabled() || !IsSupportedImageFormat(Format))
6775
return false;
6876

6977
// Disable cache for ITT-profiled images.
@@ -79,25 +87,42 @@ bool PersistentDeviceCodeCache::isImageCached(const RTDeviceBinaryImage &Img) {
7987

8088
// Make sure that image size is between caching thresholds if they are set.
8189
// Zero values for threshold is treated as disabled threshold.
82-
if ((MaxImgSize && (Img.getSize() > MaxImgSize)) ||
83-
(MinImgSize && (Img.getSize() < MinImgSize)))
90+
size_t TotalSize = 0;
91+
for (const RTDeviceBinaryImage *Img : Imgs)
92+
TotalSize += Img->getSize();
93+
if ((MaxImgSize && (TotalSize > MaxImgSize)) ||
94+
(MinImgSize && (TotalSize < MinImgSize)))
8495
return false;
8596

8697
return true;
8798
}
8899

89-
/* Stores built program in persisten cache
100+
static std::vector<const RTDeviceBinaryImage *>
101+
getSortedImages(const std::vector<const RTDeviceBinaryImage *> &Imgs) {
102+
std::vector<const RTDeviceBinaryImage *> SortedImgs = Imgs;
103+
std::sort(SortedImgs.begin(), SortedImgs.end(),
104+
[](const RTDeviceBinaryImage *A, const RTDeviceBinaryImage *B) {
105+
// All entry names are unique among these images, so comparing the
106+
// first ones is enough.
107+
return std::strcmp(A->getRawData().EntriesBegin->name,
108+
B->getRawData().EntriesBegin->name) < 0;
109+
});
110+
return SortedImgs;
111+
}
112+
113+
/* Stores built program in persistent cache
90114
*/
91115
void PersistentDeviceCodeCache::putItemToDisc(
92-
const device &Device, const RTDeviceBinaryImage &Img,
116+
const device &Device, const std::vector<const RTDeviceBinaryImage *> &Imgs,
93117
const SerializedObj &SpecConsts, const std::string &BuildOptionsString,
94118
const sycl::detail::pi::PiProgram &NativePrg) {
95119

96-
if (!isImageCached(Img))
120+
if (!areImagesCacheable(Imgs))
97121
return;
98122

123+
std::vector<const RTDeviceBinaryImage *> SortedImgs = getSortedImages(Imgs);
99124
std::string DirName =
100-
getCacheItemPath(Device, Img, SpecConsts, BuildOptionsString);
125+
getCacheItemPath(Device, SortedImgs, SpecConsts, BuildOptionsString);
101126

102127
if (DirName.empty())
103128
return;
@@ -139,7 +164,7 @@ void PersistentDeviceCodeCache::putItemToDisc(
139164
std::string FullFileName = FileName + ".bin";
140165
writeBinaryDataToFile(FullFileName, Result);
141166
trace("device binary has been cached: " + FullFileName);
142-
writeSourceItem(FileName + ".src", Device, Img, SpecConsts,
167+
writeSourceItem(FileName + ".src", Device, SortedImgs, SpecConsts,
143168
BuildOptionsString);
144169
} else {
145170
PersistentDeviceCodeCache::trace("cache lock not owned " + FileName);
@@ -160,14 +185,15 @@ void PersistentDeviceCodeCache::putItemToDisc(
160185
* stored in vector of chars.
161186
*/
162187
std::vector<std::vector<char>> PersistentDeviceCodeCache::getItemFromDisc(
163-
const device &Device, const RTDeviceBinaryImage &Img,
188+
const device &Device, const std::vector<const RTDeviceBinaryImage *> &Imgs,
164189
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {
165190

166-
if (!isImageCached(Img))
191+
if (!areImagesCacheable(Imgs))
167192
return {};
168193

194+
std::vector<const RTDeviceBinaryImage *> SortedImgs = getSortedImages(Imgs);
169195
std::string Path =
170-
getCacheItemPath(Device, Img, SpecConsts, BuildOptionsString);
196+
getCacheItemPath(Device, SortedImgs, SpecConsts, BuildOptionsString);
171197

172198
if (Path.empty() || !OSUtil::isPathPresent(Path))
173199
return {};
@@ -179,7 +205,7 @@ std::vector<std::vector<char>> PersistentDeviceCodeCache::getItemFromDisc(
179205
OSUtil::isPathPresent(FileName + ".src")) {
180206

181207
if (!LockCacheItem::isLocked(FileName) &&
182-
isCacheItemSrcEqual(FileName + ".src", Device, Img, SpecConsts,
208+
isCacheItemSrcEqual(FileName + ".src", Device, SortedImgs, SpecConsts,
183209
BuildOptionsString)) {
184210
try {
185211
std::string FullFileName = FileName + ".bin";
@@ -256,12 +282,12 @@ PersistentDeviceCodeCache::readBinaryDataFromFile(const std::string &FileName) {
256282

257283
/* Writing cache item key sources to be used for reliable identification
258284
* Format: Four pairs of [size, value] for device, build options, specialization
259-
* constant values, device code SPIR-V image.
285+
* constant values, device code SPIR-V images.
260286
*/
261287
void PersistentDeviceCodeCache::writeSourceItem(
262288
const std::string &FileName, const device &Device,
263-
const RTDeviceBinaryImage &Img, const SerializedObj &SpecConsts,
264-
const std::string &BuildOptionsString) {
289+
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
290+
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {
265291
std::ofstream FileStream{FileName, std::ios::binary};
266292

267293
std::string DeviceString{getDeviceIDString(Device)};
@@ -277,9 +303,13 @@ void PersistentDeviceCodeCache::writeSourceItem(
277303
FileStream.write((char *)&Size, sizeof(Size));
278304
FileStream.write((const char *)SpecConsts.data(), Size);
279305

280-
Size = Img.getSize();
306+
Size = 0;
307+
for (const RTDeviceBinaryImage *Img : SortedImgs)
308+
Size += Img->getSize();
281309
FileStream.write((char *)&Size, sizeof(Size));
282-
FileStream.write((const char *)Img.getRawData().BinaryStart, Size);
310+
for (const RTDeviceBinaryImage *Img : SortedImgs)
311+
FileStream.write((const char *)Img->getRawData().BinaryStart,
312+
Img->getSize());
283313
FileStream.close();
284314

285315
if (FileStream.fail()) {
@@ -292,12 +322,14 @@ void PersistentDeviceCodeCache::writeSourceItem(
292322
*/
293323
bool PersistentDeviceCodeCache::isCacheItemSrcEqual(
294324
const std::string &FileName, const device &Device,
295-
const RTDeviceBinaryImage &Img, const SerializedObj &SpecConsts,
296-
const std::string &BuildOptionsString) {
325+
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
326+
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {
297327
std::ifstream FileStream{FileName, std::ios::binary};
298328

299-
std::string ImgString{(const char *)Img.getRawData().BinaryStart,
300-
Img.getSize()};
329+
std::string ImgsString;
330+
for (const RTDeviceBinaryImage *Img : SortedImgs)
331+
ImgsString.append((const char *)Img->getRawData().BinaryStart,
332+
Img->getSize());
301333
std::string SpecConstsString{(const char *)SpecConsts.data(),
302334
SpecConsts.size()};
303335

@@ -323,7 +355,7 @@ bool PersistentDeviceCodeCache::isCacheItemSrcEqual(
323355
FileStream.read((char *)&Size, sizeof(Size));
324356
res.resize(Size);
325357
FileStream.read(&res[0], Size);
326-
if (ImgString.compare(res))
358+
if (ImgsString.compare(res))
327359
return false;
328360

329361
FileStream.close();
@@ -335,29 +367,31 @@ bool PersistentDeviceCodeCache::isCacheItemSrcEqual(
335367
return true;
336368
}
337369

338-
/* Returns directory name to store specific kernel image for specified
370+
/* Returns directory name to store specific kernel images for specified
339371
* device, build options and specialization constants values.
340372
*/
341373
std::string PersistentDeviceCodeCache::getCacheItemPath(
342-
const device &Device, const RTDeviceBinaryImage &Img,
374+
const device &Device, const std::vector<const RTDeviceBinaryImage *> &Imgs,
343375
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {
344376
std::string cache_root{getRootDir()};
345377
if (cache_root.empty()) {
346378
trace("Disable persistent cache due to unconfigured cache root.");
347379
return {};
348380
}
349381

350-
std::string ImgString = "";
351-
if (Img.getRawData().BinaryStart)
352-
ImgString.assign((const char *)Img.getRawData().BinaryStart, Img.getSize());
382+
std::string ImgsString;
383+
for (const RTDeviceBinaryImage *Img : Imgs)
384+
if (Img->getRawData().BinaryStart)
385+
ImgsString.append((const char *)Img->getRawData().BinaryStart,
386+
Img->getSize());
353387

354388
std::string DeviceString{getDeviceIDString(Device)};
355389
std::string SpecConstsString{(const char *)SpecConsts.data(),
356390
SpecConsts.size()};
357391
std::hash<std::string> StringHasher{};
358392

359393
return cache_root + "/" + std::to_string(StringHasher(DeviceString)) + "/" +
360-
std::to_string(StringHasher(ImgString)) + "/" +
394+
std::to_string(StringHasher(ImgsString)) + "/" +
361395
std::to_string(StringHasher(SpecConstsString)) + "/" +
362396
std::to_string(StringHasher(BuildOptionsString));
363397
}

sycl/source/detail/persistent_device_code_cache.hpp

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class PersistentDeviceCodeCache {
6969
* <cache_root> - root directory storing cache files;
7070
* <device_hash> - hash out of device information used to
7171
* identify target device;
72-
* <device_image_hash> - hash made out of device image used as
72+
* <device_image_hash> - hash made out of device images used as
7373
* input for the JIT compilation;
7474
* <spec_constants_values_hash> - hash for specialization constants values;
7575
* <build_options_hash> - hash for all build options;
@@ -80,7 +80,7 @@ class PersistentDeviceCodeCache {
8080
* started from 0).
8181
* Two files per cache item are stored on disk:
8282
* <n>.src - contains full values for build parameters (device information,
83-
* specialization constant values, build options, device image)
83+
* specialization constant values, build options, device images)
8484
* which is used to resolve hash collisions and analysis of
8585
* cached items.
8686
* <n>.bin - contains built device code.
@@ -108,20 +108,20 @@ class PersistentDeviceCodeCache {
108108

109109
/* Writing cache item key sources to be used for reliable identification
110110
* Format: Four pairs of [size, value] for device, build options,
111-
* specialization constant values, device code SPIR-V image.
111+
* specialization constant values, device code SPIR-V images.
112112
*/
113-
static void writeSourceItem(const std::string &FileName, const device &Device,
114-
const RTDeviceBinaryImage &Img,
115-
const SerializedObj &SpecConsts,
116-
const std::string &BuildOptionsString);
113+
static void
114+
writeSourceItem(const std::string &FileName, const device &Device,
115+
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
116+
const SerializedObj &SpecConsts,
117+
const std::string &BuildOptionsString);
117118

118119
/* Check that cache item key sources are equal to the current program
119120
*/
120-
static bool isCacheItemSrcEqual(const std::string &FileName,
121-
const device &Device,
122-
const RTDeviceBinaryImage &Img,
123-
const SerializedObj &SpecConsts,
124-
const std::string &BuildOptionsString);
121+
static bool isCacheItemSrcEqual(
122+
const std::string &FileName, const device &Device,
123+
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
124+
const SerializedObj &SpecConsts, const std::string &BuildOptionsString);
125125

126126
/* Check if on-disk cache enabled.
127127
*/
@@ -133,9 +133,10 @@ class PersistentDeviceCodeCache {
133133
/* Form string representing device version */
134134
static std::string getDeviceIDString(const device &Device);
135135

136-
/* Returns true if specified image should be cached on disk. It checks if
137-
* cache is enabled, image has SPIRV type and matches thresholds. */
138-
static bool isImageCached(const RTDeviceBinaryImage &Img);
136+
/* Returns true if specified images should be cached on disk. It checks if
137+
* cache is enabled, images have SPIRV type and match thresholds. */
138+
static bool areImagesCacheable(
139+
const std::vector<const RTDeviceBinaryImage *> &SortedImgs);
139140

140141
/* Returns value of specified parameter. Default value is used if failure
141142
* happens during obtaining value. */
@@ -162,27 +163,30 @@ class PersistentDeviceCodeCache {
162163
public:
163164
/* Get directory name for storing current cache item
164165
*/
165-
static std::string getCacheItemPath(const device &Device,
166-
const RTDeviceBinaryImage &Img,
167-
const SerializedObj &SpecConsts,
168-
const std::string &BuildOptionsString);
166+
static std::string
167+
getCacheItemPath(const device &Device,
168+
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
169+
const SerializedObj &SpecConsts,
170+
const std::string &BuildOptionsString);
169171

170172
/* Program binaries built for one or more devices are read from persistent
171173
* cache and returned in form of vector of programs. Each binary program is
172174
* stored in vector of chars.
173175
*/
174176
static std::vector<std::vector<char>>
175-
getItemFromDisc(const device &Device, const RTDeviceBinaryImage &Img,
177+
getItemFromDisc(const device &Device,
178+
const std::vector<const RTDeviceBinaryImage *> &Imgs,
176179
const SerializedObj &SpecConsts,
177180
const std::string &BuildOptionsString);
178181

179-
/* Stores build program in persisten cache
182+
/* Stores build program in persistent cache
180183
*/
181-
static void putItemToDisc(const device &Device,
182-
const RTDeviceBinaryImage &Img,
183-
const SerializedObj &SpecConsts,
184-
const std::string &BuildOptionsString,
185-
const sycl::detail::pi::PiProgram &NativePrg);
184+
static void
185+
putItemToDisc(const device &Device,
186+
const std::vector<const RTDeviceBinaryImage *> &Imgs,
187+
const SerializedObj &SpecConsts,
188+
const std::string &BuildOptionsString,
189+
const sycl::detail::pi::PiProgram &NativePrg);
186190

187191
/* Sends message to std:cerr stream when SYCL_CACHE_TRACE environemnt is set*/
188192
static void trace(const std::string &msg) {

0 commit comments

Comments
 (0)