Skip to content

Commit f0283fc

Browse files
[SYCL] Allow native OpenCL and L0 executable binaries in persistent cache (#6256)
These changes expand the persistent device code cache to allow executable binaries produced by IGC for both OpenCL and L0 to be cached. Signed-off-by: Larsen, Steffen <[email protected]>
1 parent 9ecc74b commit f0283fc

File tree

3 files changed

+62
-15
lines changed

3 files changed

+62
-15
lines changed

sycl/source/detail/persistent_device_code_cache.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,17 @@ LockCacheItem::~LockCacheItem() {
4747
FileName);
4848
}
4949

50+
// Returns true if the specified format is either SPIRV or a native binary.
51+
static bool IsSupportedImageFormat(RT::PiDeviceBinaryType Format) {
52+
return Format == PI_DEVICE_BINARY_TYPE_SPIRV ||
53+
Format == PI_DEVICE_BINARY_TYPE_NATIVE;
54+
}
55+
5056
/* Returns true if specified image should be cached on disk. It checks if
51-
* cache is enabled, image has SPIRV type and matches thresholds. */
57+
* cache is enabled, image has supported format and matches thresholds. */
5258
bool PersistentDeviceCodeCache::isImageCached(const RTDeviceBinaryImage &Img) {
53-
// Cache shoould be enabled and image type should be SPIR-V
54-
if (!isEnabled() || Img.getFormat() != PI_DEVICE_BINARY_TYPE_SPIRV)
59+
// Cache should be enabled and image type is one of the supported formats.
60+
if (!isEnabled() || !IsSupportedImageFormat(Img.getFormat()))
5561
return false;
5662

5763
// Disable cache for ITT-profiled images.

sycl/source/detail/pi.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,22 +684,54 @@ DeviceBinaryImage::getProperty(const char *PropName) const {
684684
return *It;
685685
}
686686

687+
// Returns the e_type field from an ELF image.
688+
static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize) {
689+
bool IsBigEndian = ImgData[5] == 2;
690+
if (IsBigEndian)
691+
return (static_cast<uint16_t>(ImgData[16]) << 8) |
692+
static_cast<uint16_t>(ImgData[17]);
693+
uint16_t HdrType = 0;
694+
std::copy(ImgData + 16, ImgData + 16 + sizeof(HdrType),
695+
reinterpret_cast<char *>(&HdrType));
696+
return HdrType;
697+
}
698+
687699
RT::PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData,
688700
size_t ImgSize) {
701+
// Top-level magic numbers for the recognized binary image formats.
689702
struct {
690703
RT::PiDeviceBinaryType Fmt;
691704
const uint32_t Magic;
692705
} Fmts[] = {{PI_DEVICE_BINARY_TYPE_SPIRV, 0x07230203},
693-
{PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE, 0xDEC04342}};
706+
{PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE, 0xDEC04342},
707+
// 'I', 'N', 'T', 'C' ; Intel native
708+
{PI_DEVICE_BINARY_TYPE_NATIVE, 0x43544E49}};
694709

695710
if (ImgSize >= sizeof(Fmts[0].Magic)) {
696711
detail::remove_const_t<decltype(Fmts[0].Magic)> Hdr = 0;
697712
std::copy(ImgData, ImgData + sizeof(Hdr), reinterpret_cast<char *>(&Hdr));
698713

714+
// Check headers for direct formats.
699715
for (const auto &Fmt : Fmts) {
700716
if (Hdr == Fmt.Magic)
701717
return Fmt.Fmt;
702718
}
719+
720+
// ELF e_type for recognized binary image formats.
721+
struct {
722+
RT::PiDeviceBinaryType Fmt;
723+
const uint16_t Magic;
724+
} ELFFmts[] = {{PI_DEVICE_BINARY_TYPE_NATIVE, 0xFF04}}; // OpenCL executable
725+
726+
// ELF files need to be parsed separately. The header type ends after 18
727+
// bytes.
728+
if (Hdr == 0x464c457F && ImgSize >= 18) {
729+
uint16_t HdrType = getELFHeaderType(ImgData, ImgSize);
730+
for (const auto &ELFFmt : ELFFmts) {
731+
if (HdrType == ELFFmt.Magic)
732+
return ELFFmt.Fmt;
733+
}
734+
}
703735
}
704736
return PI_DEVICE_BINARY_TYPE_NONE;
705737
}

sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//==----- PersistenDeviceCodeCache.cpp --- Persistent cache tests ----------==//
1+
//==----- PersistentDeviceCodeCache.cpp --- Persistent cache tests ---------==//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
@@ -78,7 +78,8 @@ static pi_result redefinedProgramGetInfo(pi_program program,
7878
return PI_SUCCESS;
7979
}
8080

81-
class PersistenDeviceCodeCache : public ::testing::Test {
81+
class PersistentDeviceCodeCache
82+
: public ::testing::TestWithParam<pi_device_binary_type> {
8283
public:
8384
#ifdef _WIN32
8485
int setenv(const char *name, const char *value, int overwrite) {
@@ -123,6 +124,8 @@ class PersistenDeviceCodeCache : public ::testing::Test {
123124
EXPECT_NE(getenv("SYCL_CACHE_DIR"), nullptr)
124125
<< "Please set SYCL_CACHE_DIR environment variable pointing to cache "
125126
"location.";
127+
// Set binary format from parameter.
128+
BinStruct.Format = GetParam();
126129
}
127130

128131
virtual void TearDown() {
@@ -133,7 +136,7 @@ class PersistenDeviceCodeCache : public ::testing::Test {
133136
: nullptr);
134137
}
135138

136-
PersistenDeviceCodeCache() : Plt{default_selector()} {
139+
PersistentDeviceCodeCache() : Plt{default_selector()} {
137140

138141
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
139142
std::clog << "This test is only supported on OpenCL devices\n";
@@ -199,9 +202,10 @@ class PersistenDeviceCodeCache : public ::testing::Test {
199202
detail::OSModuleHandle ModuleHandle = detail::OSUtil::ExeModuleHandle;
200203
platform Plt;
201204
device Dev;
205+
// NOTE: Format is a parameter of the test so use none and set in SetUp.
202206
pi_device_binary_struct BinStruct{/*Version*/ 1,
203207
/*Kind*/ 4,
204-
/*Format*/ PI_DEVICE_BINARY_TYPE_SPIRV,
208+
/*Format*/ PI_DEVICE_BINARY_TYPE_NONE,
205209
/*DeviceTargetSpec*/ nullptr,
206210
/*CompileOptions*/ nullptr,
207211
/*LinkOptions*/ nullptr,
@@ -221,7 +225,7 @@ class PersistenDeviceCodeCache : public ::testing::Test {
221225

222226
/* Checks that key values with \0 symbols are processed correctly
223227
*/
224-
TEST_F(PersistenDeviceCodeCache, KeysWithNullTermSymbol) {
228+
TEST_P(PersistentDeviceCodeCache, KeysWithNullTermSymbol) {
225229
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
226230
return;
227231
}
@@ -254,21 +258,21 @@ TEST_F(PersistenDeviceCodeCache, KeysWithNullTermSymbol) {
254258
/* Do read/write for the same cache item to/from 300 threads for small device
255259
* code size. Make sure that there is no data corruption or crashes.
256260
*/
257-
TEST_F(PersistenDeviceCodeCache, ConcurentReadWriteSmallItem) {
261+
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteSmallItem) {
258262
ConcurentReadWriteCache(0, 300);
259263
}
260264

261265
/* Do read/write for the same cache item to/from 100 threads for medium device
262266
* code size. Make sure that there is no data corruption or crashes.
263267
*/
264-
TEST_F(PersistenDeviceCodeCache, ConcurentReadWriteCacheMediumItem) {
268+
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheMediumItem) {
265269
ConcurentReadWriteCache(1, 100);
266270
}
267271

268272
/* Do read/write for the same cache item to/from 20 threads from big device
269273
* code size. Make sure that there is no data corruption or crashes.
270274
*/
271-
TEST_F(PersistenDeviceCodeCache, ConcurentReadWriteCacheBigItem) {
275+
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheBigItem) {
272276
ConcurentReadWriteCache(2, 20);
273277
}
274278

@@ -279,7 +283,7 @@ TEST_F(PersistenDeviceCodeCache, ConcurentReadWriteCacheBigItem) {
279283
* - source file is corrupted;
280284
* - binary file is corrupted.
281285
*/
282-
TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
286+
TEST_P(PersistentDeviceCodeCache, CorruptedCacheFiles) {
283287
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
284288
return;
285289
}
@@ -349,7 +353,7 @@ TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
349353
* - new cache item is created if existing one is locked on write operation;
350354
* - cache miss happens on read operation.
351355
*/
352-
TEST_F(PersistenDeviceCodeCache, LockFile) {
356+
TEST_P(PersistentDeviceCodeCache, LockFile) {
353357
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
354358
return;
355359
}
@@ -405,7 +409,7 @@ TEST_F(PersistenDeviceCodeCache, LockFile) {
405409
// llvm::sys::fs::setPermissions does not make effect on Windows
406410
/* Checks cache behavior when filesystem read/write operations fail
407411
*/
408-
TEST_F(PersistenDeviceCodeCache, AccessDeniedForCacheDir) {
412+
TEST_P(PersistentDeviceCodeCache, AccessDeniedForCacheDir) {
409413
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
410414
return;
411415
}
@@ -452,4 +456,9 @@ TEST_F(PersistenDeviceCodeCache, AccessDeniedForCacheDir) {
452456
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(ItemDir));
453457
}
454458
#endif //_WIN32
459+
460+
INSTANTIATE_TEST_SUITE_P(PersistentDeviceCodeCacheImpl,
461+
PersistentDeviceCodeCache,
462+
::testing::Values(PI_DEVICE_BINARY_TYPE_SPIRV,
463+
PI_DEVICE_BINARY_TYPE_NATIVE));
455464
} // namespace

0 commit comments

Comments
 (0)