Skip to content

[SYCL] Allow native OpenCL and L0 executable binaries in persistent cache #6256

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
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
12 changes: 9 additions & 3 deletions sycl/source/detail/persistent_device_code_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ LockCacheItem::~LockCacheItem() {
FileName);
}

// Returns true if the specified format is either SPIRV or a native binary.
static bool IsSupportedImageFormat(RT::PiDeviceBinaryType Format) {
return Format == PI_DEVICE_BINARY_TYPE_SPIRV ||
Format == PI_DEVICE_BINARY_TYPE_NATIVE;
}

/* Returns true if specified image should be cached on disk. It checks if
* cache is enabled, image has SPIRV type and matches thresholds. */
* cache is enabled, image has supported format and matches thresholds. */
bool PersistentDeviceCodeCache::isImageCached(const RTDeviceBinaryImage &Img) {
// Cache shoould be enabled and image type should be SPIR-V
if (!isEnabled() || Img.getFormat() != PI_DEVICE_BINARY_TYPE_SPIRV)
// Cache should be enabled and image type is one of the supported formats.
if (!isEnabled() || !IsSupportedImageFormat(Img.getFormat()))
return false;

// Disable cache for ITT-profiled images.
Expand Down
34 changes: 33 additions & 1 deletion sycl/source/detail/pi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,22 +684,54 @@ DeviceBinaryImage::getProperty(const char *PropName) const {
return *It;
}

// Returns the e_type field from an ELF image.
static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize) {
bool IsBigEndian = ImgData[5] == 2;
if (IsBigEndian)
return (static_cast<uint16_t>(ImgData[16]) << 8) |
static_cast<uint16_t>(ImgData[17]);
uint16_t HdrType = 0;
std::copy(ImgData + 16, ImgData + 16 + sizeof(HdrType),
reinterpret_cast<char *>(&HdrType));
return HdrType;
}

RT::PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData,
size_t ImgSize) {
// Top-level magic numbers for the recognized binary image formats.
struct {
RT::PiDeviceBinaryType Fmt;
const uint32_t Magic;
} Fmts[] = {{PI_DEVICE_BINARY_TYPE_SPIRV, 0x07230203},
{PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE, 0xDEC04342}};
{PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE, 0xDEC04342},
// 'I', 'N', 'T', 'C' ; Intel native
{PI_DEVICE_BINARY_TYPE_NATIVE, 0x43544E49}};

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

// Check headers for direct formats.
for (const auto &Fmt : Fmts) {
if (Hdr == Fmt.Magic)
return Fmt.Fmt;
}

// ELF e_type for recognized binary image formats.
struct {
RT::PiDeviceBinaryType Fmt;
const uint16_t Magic;
} ELFFmts[] = {{PI_DEVICE_BINARY_TYPE_NATIVE, 0xFF04}}; // OpenCL executable

// ELF files need to be parsed separately. The header type ends after 18
// bytes.
if (Hdr == 0x464c457F && ImgSize >= 18) {
uint16_t HdrType = getELFHeaderType(ImgData, ImgSize);
for (const auto &ELFFmt : ELFFmts) {
if (HdrType == ELFFmt.Magic)
return ELFFmt.Fmt;
}
}
}
return PI_DEVICE_BINARY_TYPE_NONE;
}
Expand Down
31 changes: 20 additions & 11 deletions sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//==----- PersistenDeviceCodeCache.cpp --- Persistent cache tests ----------==//
//==----- PersistentDeviceCodeCache.cpp --- Persistent cache tests ---------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down Expand Up @@ -78,7 +78,8 @@ static pi_result redefinedProgramGetInfo(pi_program program,
return PI_SUCCESS;
}

class PersistenDeviceCodeCache : public ::testing::Test {
class PersistentDeviceCodeCache
: public ::testing::TestWithParam<pi_device_binary_type> {
public:
#ifdef _WIN32
int setenv(const char *name, const char *value, int overwrite) {
Expand Down Expand Up @@ -123,6 +124,8 @@ class PersistenDeviceCodeCache : public ::testing::Test {
EXPECT_NE(getenv("SYCL_CACHE_DIR"), nullptr)
<< "Please set SYCL_CACHE_DIR environment variable pointing to cache "
"location.";
// Set binary format from parameter.
BinStruct.Format = GetParam();
}

virtual void TearDown() {
Expand All @@ -133,7 +136,7 @@ class PersistenDeviceCodeCache : public ::testing::Test {
: nullptr);
}

PersistenDeviceCodeCache() : Plt{default_selector()} {
PersistentDeviceCodeCache() : Plt{default_selector()} {

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

/* Checks that key values with \0 symbols are processed correctly
*/
TEST_F(PersistenDeviceCodeCache, KeysWithNullTermSymbol) {
TEST_P(PersistentDeviceCodeCache, KeysWithNullTermSymbol) {
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
return;
}
Expand Down Expand Up @@ -254,21 +258,21 @@ TEST_F(PersistenDeviceCodeCache, KeysWithNullTermSymbol) {
/* Do read/write for the same cache item to/from 300 threads for small device
* code size. Make sure that there is no data corruption or crashes.
*/
TEST_F(PersistenDeviceCodeCache, ConcurentReadWriteSmallItem) {
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteSmallItem) {
ConcurentReadWriteCache(0, 300);
}

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

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

Expand All @@ -279,7 +283,7 @@ TEST_F(PersistenDeviceCodeCache, ConcurentReadWriteCacheBigItem) {
* - source file is corrupted;
* - binary file is corrupted.
*/
TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
TEST_P(PersistentDeviceCodeCache, CorruptedCacheFiles) {
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
return;
}
Expand Down Expand Up @@ -349,7 +353,7 @@ TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
* - new cache item is created if existing one is locked on write operation;
* - cache miss happens on read operation.
*/
TEST_F(PersistenDeviceCodeCache, LockFile) {
TEST_P(PersistentDeviceCodeCache, LockFile) {
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
return;
}
Expand Down Expand Up @@ -405,7 +409,7 @@ TEST_F(PersistenDeviceCodeCache, LockFile) {
// llvm::sys::fs::setPermissions does not make effect on Windows
/* Checks cache behavior when filesystem read/write operations fail
*/
TEST_F(PersistenDeviceCodeCache, AccessDeniedForCacheDir) {
TEST_P(PersistentDeviceCodeCache, AccessDeniedForCacheDir) {
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
return;
}
Expand Down Expand Up @@ -452,4 +456,9 @@ TEST_F(PersistenDeviceCodeCache, AccessDeniedForCacheDir) {
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(ItemDir));
}
#endif //_WIN32

INSTANTIATE_TEST_SUITE_P(PersistentDeviceCodeCacheImpl,
PersistentDeviceCodeCache,
::testing::Values(PI_DEVICE_BINARY_TYPE_SPIRV,
PI_DEVICE_BINARY_TYPE_NATIVE));
} // namespace