-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
cranelift: Use cranelift-jit
in runtests
#4453
Conversation
Subscribe to Label Actioncc @fitzgen
This issue or pull request has been labeled: "cranelift", "fuzzing"
Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
c15a323
to
67518ee
Compare
3e13a39
to
3e158aa
Compare
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.
Thanks for this! The change overall looks reasonable. I'm not sure about the Windows runtime issue; tagged @peterhuene for more thoughts.
23824ab
to
32f167a
Compare
32f167a
to
497be14
Compare
Using `cranelift-jit` in run tests allows us to preform relocations and libcalls. This is important since some instruction lowerings fallback to libcall's when an extension is missing, or when it's too complicated to implement manually. This is also a first step to being able to test `call`'s between functions in the runtest suite. It should also make it easier to eventually test TLS relocations, symbol resolution and ABI's. Another benefit of this is that we also get to test the JIT more, since it now runs the runtests, and gets some fuzzing via `fuzzgen` (which uses the `SingleFunctionCompiler`). This change causes regressions in terms of runtime for the filetests. I haven't done any serious benchmarking but what I've been seeing is that it now takes about ~3 seconds to run the testsuite while it previously took around 2 seconds.
497be14
to
cfb1b80
Compare
With the CRT issue resolved I think this is ready to merge. The only changes since the last review were a rebase and enabling the FMA tests that we couldn't enable in #4460. Thanks for reviewing! |
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.
Overall I think this is great. I'd just like to take a little more time on ownership of TargetIsa
and reuse of SingleFunctionCompiler
. I'm open to merging it as-is if you feel that it's better this way, @afonso360, but it seems to me that it's useful to be able to reuse these.
@@ -66,27 +66,47 @@ impl SingleFunctionCompiler { | |||
/// - compile the [Function] | |||
/// - compile a `Trampoline` for the [Function]'s signature (or used a cached `Trampoline`; | |||
/// this makes it possible to call functions when the signature is not known until runtime. | |||
pub fn compile(&mut self, function: Function) -> Result<CompiledFunction, CompilationError> { | |||
pub fn compile(self, function: Function) -> Result<CompiledFunction, CompilationError> { |
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.
Changing SingleFunctionCompiler::compile
from taking &mut self
to just self
feels unfortunate, since it forces callers to build a new TargetIsa
for every function they compile. What would you think of changing JITBuilder
to take a shared reference instead? Either &dyn TargetIsa
or Rc<dyn TargetIsa>
, whichever is easier. In the latter case, SingleFunctionCompiler
would also take an Rc
instead of a Box
.
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 remember (sorry, this was a while ago) trying to change to &dyn TargetIsa
, but it brought a bunch of changes due to lifetimes, and I gave up on that path.
I didn't try Rc<>
but see the comment down below.
@@ -691,7 +691,7 @@ where | |||
let sig = self.generate_signature()?; | |||
|
|||
let mut fn_builder_ctx = FunctionBuilderContext::new(); | |||
let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone()); | |||
let mut func = Function::with_name_signature(ExternalName::user(0, 1), sig.clone()); |
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 is this change for?
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 name user(0, 0)
was the trampoline IIRC and the JIT was complaining about it. I'm not too sure, but I can go check.
// We can't use the requested ISA directly since it does not contain info | ||
// about the operating system / calling convention / etc.. | ||
// | ||
// Copy the requested ISA flags into the host ISA and use that. | ||
let isa = build_host_isa(false, context.flags.clone(), requested_isa.isa_flags()); | ||
|
||
let compiled_fn = | ||
SingleFunctionCompiler::new(isa).compile(func.clone().into_owned())?; |
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'd prefer not to move this code into the loop, if my earlier suggestion on shared references to the TargetIsa
works out.
let isa = create_target_isa(&test_file.isa_spec)?; | ||
let compiled_fn = SingleFunctionCompiler::new(isa).compile(func.clone())?; |
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'd prefer not to move this code into the loop, if my earlier suggestion on shared references to the TargetIsa
works out.
// Build and declare the trampoline in the module | ||
let trampoline_name = format!("{}", trampoline.name); | ||
let trampoline_id = | ||
module.declare_function(&trampoline_name, Linkage::Local, &trampoline.signature)?; |
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.
If it works out to keep the SingleFunctionCompiler
reusable, do you think it'd be worth keeping the cache of trampolines around too?
@jameysharp I agree with your comments, however this is sort of an intermediate PR with the follow up cleaning pretty much all of it. See #4667, we do away with SingleFunctionCompiler and link the entire test file at once, so the repeated compilation issue goes away. I'd prefer not to have to clean this up, since it's going away as soon as that is done. But let me know if this is a blocker. |
I hadn't looked at 4667 yet, and that resolves my concerns. Thanks! |
As of this commit, I'm now seeing test failures on s390x (Ubuntu 20.04), specifically when running
when running the sample code in
Note that this attempts to use Instead, you should use separate |
👋 Hey,
Edit: Ignore that, I misread your comment and thought that only the doc tests were failing.
If so, this might be related to: #4986 |
No, only the doc tests are indeed failing. I've been debugging this right now, and the difference is that doc test sample program is single-threaded and uses the main heap, where How would I use the |
That's interesting, and weird!
This should do it. However I think that we probably should switch to a mmap allocator since that apparently can solve a bunch of other issues with cranelift-jit. |
The sample program in cranelift/filetests/src/function_runner.rs would abort with an mprotect failure under certain circumstances, see bytecodealliance#4453 (comment) Root cause was that enabling PROT_EXEC on the main process heap may be prohibited, depending on Linux distro and version. This only shows up in the doc test sample program because the main clif-util is multi-threaded and therefore allocations will happen on glibc's per-thread heap, which is allocated via mmap, and not the main process heap. Work around the problem by enabling the "selinux-fix" feature of the cranelift-jit crate dependency in the filetests. Note that this didn't compile out of the box, so a separate fix is also required and provided as part of this PR. Going forward, it would be preferable to always use mmap to allocate the backing memory for JITted code.
The sample program in cranelift/filetests/src/function_runner.rs would abort with an mprotect failure under certain circumstances, see bytecodealliance#4453 (comment) Root cause was that enabling PROT_EXEC on the main process heap may be prohibited, depending on Linux distro and version. This only shows up in the doc test sample program because the main clif-util is multi-threaded and therefore allocations will happen on glibc's per-thread heap, which is allocated via mmap, and not the main process heap. Work around the problem by enabling the "selinux-fix" feature of the cranelift-jit crate dependency in the filetests. Note that this didn't compile out of the box, so a separate fix is also required and provided as part of this PR. Going forward, it would be preferable to always use mmap to allocate the backing memory for JITted code.
The sample program in cranelift/filetests/src/function_runner.rs would abort with an mprotect failure under certain circumstances, see #4453 (comment) Root cause was that enabling PROT_EXEC on the main process heap may be prohibited, depending on Linux distro and version. This only shows up in the doc test sample program because the main clif-util is multi-threaded and therefore allocations will happen on glibc's per-thread heap, which is allocated via mmap, and not the main process heap. Work around the problem by enabling the "selinux-fix" feature of the cranelift-jit crate dependency in the filetests. Note that this didn't compile out of the box, so a separate fix is also required and provided as part of this PR. Going forward, it would be preferable to always use mmap to allocate the backing memory for JITted code.
👋 Hey,
This PR changes our run tests to run via
cranelift-jit
. Its based on top of #4450 so its probably not worth doing any serious review until that is merged.Using
cranelift-jit
in run tests allows us to preform relocations andlibcalls. This is important since some instruction lowerings fallback
to libcall's when an extension is missing, or when it's too complicated
to implement manually.
This is also a first step to being able to test
call
's between functionsin the runtest suite. It should also make it easier to eventually test
TLS relocations, symbol resolution and ABI's.
Another benefit of this is that we also get to test the JIT more, since
it now runs the runtests, and gets some fuzzing via
fuzzgen
(whichuses the
SingleFunctionCompiler
).This change causes regressions in terms of runtime for the filetests.
I haven't done any serious benchmarking but what I've been seeing is
that it now takes about ~3 seconds to run the testsuite while it
previously took around 2 seconds.
Edit:
This also closes #3030 since we can now do relocations in runtests