-
Notifications
You must be signed in to change notification settings - Fork 796
[SYCL] PoC implementation of kernel compiler extension with libtooling and sycl-jit #15701
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
Conversation
…oling and sycl-jit Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
sycl-jit/jit-compiler/CMakeLists.txt
Outdated
| SYSTEM PRIVATE | ||
| ${LLVM_MAIN_INCLUDE_DIR} | ||
| ${LLVM_SPIRV_INCLUDE_DIRS} | ||
| ${CMAKE_SOURCE_DIR}/../clang/include |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does LLVM CMake not define a variable for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this to use ${LLVM_EXTERNAL_CLANG_SOURCE_DIR}.
Unfortunately there doesn't seem to be an equivalent for the build directory, from which an .inc file that defines CLANG_VERSION_MAJOR is included.
| NewArgs.push_back((Twine("-resource-dir=") + DPCPPRoot + "/lib/clang/" + | ||
| Twine(CLANG_VERSION_MAJOR)) | ||
| .str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these paths also apply in a packaged release?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, a release icpx follows the same path structure (checked with -print-resource-dir).
| namespace sycl { | ||
| inline namespace _V1 { | ||
| namespace ext::oneapi::experimental { | ||
| namespace detail { | ||
|
|
||
| bool SYCLJIT_Compilation_Available() { return false; } | ||
|
|
||
| spirv_vec_t | ||
| SYCLJIT_to_SPIRV(const std::string &SYCLSource, include_pairs_t IncludePairs, | ||
| const std::vector<std::string> &UserArgs, std::string *LogPtr, | ||
| const std::vector<std::string> &RegisteredKernelNames) { | ||
| (void)SYCLSource; | ||
| (void)IncludePairs; | ||
| (void)UserArgs; | ||
| (void)LogPtr; | ||
| (void)RegisteredKernelNames; | ||
|
|
||
| throw sycl::exception(sycl::errc::build, | ||
| "kernel_compiler via sycl-jit is not available"); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With [[maybe_unused]], we should be able to avoid the double declaration and can just ifdef the body of the function. In any case, we don't need to duplicate the namespace declarations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's neat.
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
| opencl = 0, | ||
| spirv = 1, | ||
| sycl = 2 /* cuda */, | ||
| sycljit = 99 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is part of a public interface. Can we document it somewhere? Also, I don't think you need to make a jump, as long as we don't change it after it's merged.
Side note, I personally prefer sycl_jit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only temporary until we complete functionality in follow-up PRs, so not intended to ever be exposed users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I renamed the enum value and added a comment that this is temporary.
sycl/source/detail/jit_compiler.cpp
Outdated
|
|
||
| // TODO: Handle situation. | ||
| assert(RegisteredKernelNames.empty() && | ||
| "Instantiation of kernel templates NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we throw instead? In cases where asserts are disabled what would happen if execution continues from here?
Signed-off-by: Julian Oppermann <[email protected]>
| extern "C" JITResult compileSYCL(const char *SYCLSource, | ||
| View<IncludePair> IncludePairs, | ||
| View<const char *> UserArgs, | ||
| const char *DPCPPRoot) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DPCPPRoot is not like the other arguments. Doesn't it seem like the routine should be able to figure that out itself, rather than being provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense; it's detected from inside the JIT library now.
| CommandLine.append(UserArgs.begin(), UserArgs.end()); | ||
| clang::tooling::FixedCompilationDatabase DB{"./", CommandLine}; | ||
|
|
||
| constexpr auto SourcePath = "rtc.cpp"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than hard-code "rtc.cpp" in, can this 'fantasy name' for the file be an argument to the API? It might show up in debug information, so it might be useful to users to be able to disambiguate, rather than having every dynamic device compiled kernel originate with the same fictional file name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, will do 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I'm passing in a semi-random ID, same as the file-based implementation. There's no property yet in the extension to specify a file name or prefix, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the reason that a user might want to change this name? Why is it better to have a semi-random ID as a default rather than a fixed string?
I can imagine that the name might show up in error / log messages, for example, when there is a syntax error in the source string. If that's the only case the name is visible, it seems like having a fixed string like rtc.cpp would be fine, and probably preferable to a name with a random number.
I'm not opposed to adding a property which allows the user to set this name, but I think it should be an optional property because I think many people will not care what the name is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can imagine that the name might show up in error / log messages, for example, when there is a syntax error in the source string. If that's the only case the name is visible, [...]
Yes, that's the only case. I agree that the ID doesn't add much value here because we don't materialise anything on the actual filesystem. I'll keep the plumbing to pass the filename down to the JIT, but will set it rtc.cpp until there's a need and a means to modify it from the extension.
| sycl::detail::ur::getOsLibraryFuncAddress(LibraryPtr, "compileSYCL")); | ||
| if (!this->CompileSYCLHandle) { | ||
| printPerformanceWarning( | ||
| "Cannot resolve JIT library function entry point"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds more serious than a mere performance warning :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
printPerformanceWarning is the generic error message helper in sycl-jit, but yes, I agree it's a bit of a misnomer when used here (and while attempting to set-up the other entrypoints before).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reasoning behind that name is that so far, when something went wrong in sycl-jit, we would simply fall back to non-fused execution of kernels (in case of kernel fusion), which still leads to correct results, but potentially lower performance than expected.
But I'm happy to rename this function to something more suitable.
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
| spirv = 1, | ||
| sycl = 2, | ||
| /* cuda */ | ||
| sycl_jit /* temporary, alternative implementation for SYCL */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it is temporary, I think the previous value given (= 99) is a good idea. Problem is, if someone compiles with this in use and it crosses the library boundary, if we then remove it and another different enum value is added, compatibility could be broken. It's unlikely to happen, but no impossible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| // CHECK-DAG: lit.cfg.py | ||
| // | ||
| // CHECK-NUM-MATCHES: 5 | ||
| // CHECK-NUM-MATCHES: 6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What has caused this change? I don't see it used in the added test and in general we shouldn't increase this number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's in the SYCL source string in the added E2E test:
llvm/sycl/test-e2e/KernelCompiler/kernel_compiler_sycl_jit.cpp
Lines 31 to 32 in 407124b
| auto constexpr SYCLSource = R"===( | |
| #include <sycl/sycl.hpp> |
Signed-off-by: Julian Oppermann <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one nit question
| #include <memory> | ||
|
|
||
| namespace llvm { | ||
| class Module; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this forward declared and not simply included?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was just a leftover from an early design point. Changed, thanks!
| sycl::detail::ur::getOsLibraryFuncAddress(LibraryPtr, "compileSYCL")); | ||
| if (!this->CompileSYCLHandle) { | ||
| printPerformanceWarning( | ||
| "Cannot resolve JIT library function entry point"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reasoning behind that name is that so far, when something went wrong in sycl-jit, we would simply fall back to non-fused execution of kernels (in case of kernel fusion), which still leads to correct results, but potentially lower performance than expected.
But I'm happy to rename this function to something more suitable.
Signed-off-by: Julian Oppermann <[email protected]>
|
@steffenlarsen @gmlueck @AlexeySachkov Do you want to review this PR again? Or are you fine with us merging this with approval from @cperkinsintel and me? |
I'm fine with you merging the PR, my comments were very minor, feel free to ignore me here completely :) |
|
@cperkinsintel has worked closer with this feature than I have, so I trust his judgement! |
Also OK with me. I mostly review interfaces, and I think this PR does not really change the interface to the kernel compiler. |
Signed-off-by: Julian Oppermann <[email protected]>
Signed-off-by: Julian Oppermann <[email protected]>
Silences unused variable warning introduced with #15701. Signed-off-by: Julian Oppermann <[email protected]>
This PR sets up in-memory compilation for runtime-defined SYCL kernels, via clang's libtooling interface and reusing LLVM-to-SPRIV-translation infrastructure in sycl-jit. I introduced a new, undocumented source language
sycljit, which shall be removed again when the proposed approach is ready to replace the current process/file-based implementation for thesyclsource language.Missing features:
__sycl_kernelprefix when requesting a kernel from the bundlesycl-post-linkphase, so only very simple kernels are supported