-
Notifications
You must be signed in to change notification settings - Fork 795
[SYCL] Implement eviction for in-memory program cache #16062
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
steffenlarsen
merged 14 commits into
intel:sycl
from
uditagarwal97:in_mem_cache_eviction
Nov 20, 2024
Merged
Changes from 1 commit
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
8307767
Add environment variable to control eviction in in-memory cache
uditagarwal97 c04057c
Implement cache eviction
uditagarwal97 2924479
Update SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD env variable
uditagarwal97 518c758
Fix test failures
uditagarwal97 bc855cd
Add tests
uditagarwal97 6876b72
Address feedback
uditagarwal97 14963e5
Replace E2E test with unit tests. Fix races.
uditagarwal97 31880b1
Merge remote-tracking branch 'upstream/sycl' into in_mem_cache_eviction
uditagarwal97 5c68269
Fix unit tests
uditagarwal97 0e00170
Remove boost usages
uditagarwal97 b3fdca2
Add comments. Fix clang-format.
uditagarwal97 c85c220
Address reviews.
uditagarwal97 d80be2e
Merge remote-tracking branch 'upstream/sycl' into in_mem_cache_eviction
uditagarwal97 722821b
Fix build after recent changes to fast kernel cache's key.
uditagarwal97 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
225 changes: 225 additions & 0 deletions
225
sycl/unittests/kernel-and-program/InMemCacheEviction.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| //==----- InMemCacheEviction.cpp --- In-memory cache eviction tests -------==// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // This file contains tests covering eviction in in-memory program cache. | ||
|
|
||
| #define SYCL2020_DISABLE_DEPRECATION_WARNINGS | ||
|
|
||
| #include "../thread_safety/ThreadUtils.h" | ||
| #include "detail/context_impl.hpp" | ||
| #include "detail/kernel_program_cache.hpp" | ||
| #include <detail/config.hpp> | ||
| #include <helpers/MockDeviceImage.hpp> | ||
| #include <helpers/MockKernelInfo.hpp> | ||
| #include <helpers/UrMock.hpp> | ||
|
|
||
| #include <gtest/gtest.h> | ||
|
|
||
| #include <iostream> | ||
|
|
||
| using namespace sycl; | ||
|
|
||
| class Kernel1; | ||
| class Kernel2; | ||
| class Kernel3; | ||
|
|
||
| MOCK_INTEGRATION_HEADER(Kernel1) | ||
| MOCK_INTEGRATION_HEADER(Kernel2) | ||
| MOCK_INTEGRATION_HEADER(Kernel3) | ||
|
|
||
| static sycl::unittest::MockDeviceImage Img[] = { | ||
| sycl::unittest::generateDefaultImage({"Kernel1"}), | ||
| sycl::unittest::generateDefaultImage({"Kernel2"}), | ||
| sycl::unittest::generateDefaultImage({"Kernel3"})}; | ||
|
|
||
| static sycl::unittest::MockDeviceImageArray<3> ImgArray{Img}; | ||
|
|
||
| // Number of times urProgramCreateWithIL is called. This is used to check | ||
| // if the program is created or fetched from the cache. | ||
| static int NumProgramBuild = 0; | ||
|
|
||
| constexpr int ProgramSize = 10000; | ||
|
|
||
| static ur_result_t redefinedProgramCreateWithIL(void *) { | ||
| ++NumProgramBuild; | ||
| return UR_RESULT_SUCCESS; | ||
| } | ||
|
|
||
| static ur_result_t redefinedProgramGetInfoAfter(void *pParams) { | ||
| auto params = *static_cast<ur_program_get_info_params_t *>(pParams); | ||
| if (*params.ppropName == UR_PROGRAM_INFO_NUM_DEVICES) { | ||
| auto value = reinterpret_cast<unsigned int *>(*params.ppPropValue); | ||
| *value = 1; | ||
| } | ||
|
|
||
| if (*params.ppropName == UR_PROGRAM_INFO_BINARY_SIZES) { | ||
| auto value = reinterpret_cast<size_t *>(*params.ppPropValue); | ||
| value[0] = ProgramSize; | ||
| } | ||
|
|
||
| if (*params.ppropName == UR_PROGRAM_INFO_BINARIES) { | ||
| auto value = reinterpret_cast<unsigned char **>(*params.ppPropValue); | ||
| value[0] = 0; | ||
| } | ||
|
|
||
| return UR_RESULT_SUCCESS; | ||
| } | ||
|
|
||
| // Function to set SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD. | ||
| static void setCacheEvictionEnv(const char *value) { | ||
| #ifdef _WIN32 | ||
| _putenv_s("SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD", value); | ||
| #else | ||
| if (value) | ||
| setenv("SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD", value, 1); | ||
| else | ||
| (void)unsetenv("SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD"); | ||
| #endif | ||
|
|
||
| sycl::detail::readConfig(true); | ||
| sycl::detail::SYCLConfig< | ||
| sycl::detail::SYCL_IN_MEM_CACHE_EVICTION_THRESHOLD>::reset(); | ||
| } | ||
|
|
||
| // Function to check number of entries in the cache and eviction list. | ||
| static inline void | ||
| CheckNumberOfEntriesInCacheAndEvictionList(detail::context_impl &CtxImpl, | ||
| size_t ExpectedNumEntries) { | ||
| auto &KPCache = CtxImpl.getKernelProgramCache(); | ||
| EXPECT_EQ(KPCache.acquireCachedPrograms().get().size(), ExpectedNumEntries) | ||
| << "Unexpected number of entries in the cache"; | ||
| auto EvcList = KPCache.acquireEvictionList(); | ||
| EXPECT_EQ(EvcList.get().size(), ExpectedNumEntries) | ||
| << "Unexpected number of entries in the eviction list"; | ||
| } | ||
|
|
||
| class InMemCacheEvictionTests : public ::testing::Test { | ||
| protected: | ||
| void TearDown() override { setCacheEvictionEnv(""); } | ||
| }; | ||
|
|
||
| TEST(InMemCacheEvictionTests, TestBasicEvictionAndLRU) { | ||
| NumProgramBuild = 0; | ||
| sycl::unittest::UrMock<> Mock; | ||
| mock::getCallbacks().set_before_callback("urProgramCreateWithIL", | ||
| &redefinedProgramCreateWithIL); | ||
| mock::getCallbacks().set_after_callback("urProgramGetInfo", | ||
| &redefinedProgramGetInfoAfter); | ||
|
|
||
| sycl::platform Plt{sycl::platform()}; | ||
| sycl::context Ctx{Plt}; | ||
| auto CtxImpl = detail::getSyclObjImpl(Ctx); | ||
| queue q(Ctx, default_selector_v); | ||
|
|
||
| // One program is of 10000 bytes, so 20005 eviction threshold can | ||
| // accommodate two program. | ||
| setCacheEvictionEnv("20005"); | ||
|
|
||
| // Cache is empty, so one urProgramCreateWithIL call. | ||
| q.single_task<class Kernel1>([] {}); | ||
| EXPECT_EQ(NumProgramBuild, 1); | ||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 1); | ||
|
|
||
| q.single_task<class Kernel2>([] {}); | ||
| EXPECT_EQ(NumProgramBuild, 2); | ||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 2); | ||
|
|
||
| // Move first program to end of eviction list. | ||
| q.single_task<class Kernel1>([] {}); | ||
| EXPECT_EQ(NumProgramBuild, 2); | ||
|
|
||
| // Calling Kernel3, Kernel2, and Kernel1 in a cyclic manner to | ||
| // verify LRU's working. | ||
|
|
||
| // Kernel2's program should have been evicted. | ||
| q.single_task<class Kernel3>([] {}); | ||
| EXPECT_EQ(NumProgramBuild, 3); | ||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 2); | ||
|
|
||
| // Calling Kernel2 again should trigger urProgramCreateWithIL and | ||
| // should evict Kernel1's program. | ||
| q.single_task<class Kernel2>([] {}); | ||
| EXPECT_EQ(NumProgramBuild, 3); | ||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 2); | ||
|
|
||
| // Calling Kernel1 again should trigger urProgramCreateWithIL and | ||
| // should evict Kernel3's program. | ||
| q.single_task<class Kernel1>([] {}); | ||
| EXPECT_EQ(NumProgramBuild, 4); | ||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 2); | ||
| } | ||
|
|
||
| // Test to verify eviction using concurrent kernel invocation. | ||
| TEST(InMemCacheEvictionTests, TestConcurrentEvictionDifferentQueue) { | ||
| NumProgramBuild = 0; | ||
| sycl::unittest::UrMock<> Mock; | ||
| mock::getCallbacks().set_before_callback("urProgramCreateWithIL", | ||
| &redefinedProgramCreateWithIL); | ||
| mock::getCallbacks().set_after_callback("urProgramGetInfo", | ||
| &redefinedProgramGetInfoAfter); | ||
|
|
||
| sycl::platform Plt{sycl::platform()}; | ||
| context Ctx{Plt}; | ||
| auto CtxImpl = detail::getSyclObjImpl(Ctx); | ||
|
|
||
| // One program is of 10000 bytes, so 20005 eviction threshold can | ||
| // accommodate two program. | ||
| setCacheEvictionEnv("20005"); | ||
|
|
||
| constexpr size_t ThreadCount = 100; | ||
| Barrier barrier(ThreadCount); | ||
| { | ||
| auto ConcurrentInvokeKernels = [&](std::size_t threadId) { | ||
| queue q(Ctx, default_selector_v); | ||
| barrier.wait(); | ||
| q.single_task<class Kernel1>([] {}); | ||
| q.single_task<class Kernel2>([] {}); | ||
| q.single_task<class Kernel3>([] {}); | ||
| q.wait_and_throw(); | ||
| }; | ||
|
|
||
| ThreadPool MPool(ThreadCount, ConcurrentInvokeKernels); | ||
| } | ||
|
|
||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 2); | ||
| } | ||
|
|
||
| // Test to verify eviction using concurrent kernel invocation when | ||
| // cache size is very less so as to trigger immediate eviction. | ||
| TEST(InMemCacheEvictionTests, TestConcurrentEvictionSmallCache) { | ||
| NumProgramBuild = 0; | ||
| sycl::unittest::UrMock<> Mock; | ||
| mock::getCallbacks().set_before_callback("urProgramCreateWithIL", | ||
| &redefinedProgramCreateWithIL); | ||
| mock::getCallbacks().set_after_callback("urProgramGetInfo", | ||
| &redefinedProgramGetInfoAfter); | ||
|
|
||
| context Ctx{platform()}; | ||
| auto CtxImpl = detail::getSyclObjImpl(Ctx); | ||
|
|
||
| // One program is of 10000 bytes, so 100 eviction threshold will | ||
| // trigger immediate eviction. | ||
| setCacheEvictionEnv("100"); | ||
|
|
||
| // Fetch the same kernel concurrently from multiple threads. | ||
| // This should cause some threads to insert a program and other | ||
| // threads to evict the same program. | ||
| constexpr size_t ThreadCount = 300; | ||
| Barrier barrier(ThreadCount); | ||
| { | ||
| auto ConcurrentInvokeKernels = [&](std::size_t threadId) { | ||
| queue q(Ctx, default_selector_v); | ||
| barrier.wait(); | ||
| q.single_task<class Kernel1>([] {}); | ||
| q.wait_and_throw(); | ||
| }; | ||
|
|
||
| ThreadPool MPool(ThreadCount, ConcurrentInvokeKernels); | ||
| } | ||
|
|
||
| CheckNumberOfEntriesInCacheAndEvictionList(*CtxImpl, 0); | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.