Skip to content
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

Add imaging_mode support (static compilation) #125

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

jpsamaroo
Copy link
Member

@jpsamaroo jpsamaroo commented Dec 1, 2020

Requires JuliaLang/julia#38642

We can tell Julia that we want it to emit symbols instead of session-specific pointers, making our code (potentially) relocatable. I'm not locked in on this API, but it was pretty easy to implement. Known issues include Symbols embedded in the IR; they show up as {}* null in the LLVM IR for some reason. I've tested that I can roundtrip very simple functions (including closures) through codegen(:obj, ...)+dlopen/dlsym.

@codecov
Copy link

codecov bot commented Dec 2, 2020

Codecov Report

Merging #125 (b2524b5) into master (2c4a304) will decrease coverage by 8.15%.
The diff coverage is 20.00%.

❗ Current head b2524b5 differs from pull request most recent head 4b3cf11. Consider uploading reports for the commit 4b3cf11 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master     #125      +/-   ##
==========================================
- Coverage   79.79%   71.63%   -8.16%     
==========================================
  Files          22       22              
  Lines        1628     1590      -38     
==========================================
- Hits         1299     1139     -160     
- Misses        329      451     +122     
Impacted Files Coverage Δ
src/jlgen.jl 78.57% <ø> (+8.89%) ⬆️
src/native.jl 0.00% <0.00%> (-100.00%) ⬇️
src/interface.jl 51.11% <100.00%> (-26.86%) ⬇️
src/bpf.jl 0.00% <0.00%> (-92.86%) ⬇️
src/gcn.jl 0.00% <0.00%> (-67.68%) ⬇️
src/validation.jl 56.11% <0.00%> (-40.69%) ⬇️
src/error.jl 4.34% <0.00%> (-26.09%) ⬇️
src/GPUCompiler.jl 81.81% <0.00%> (-18.19%) ⬇️
... and 13 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2c4a304...4b3cf11. Read the comment docs.

@maleadt
Copy link
Member

maleadt commented Mar 3, 2021

Base PR has been merged; needs an update here?

@jpsamaroo
Copy link
Member Author

Yes indeed! How do you feel about me having the extra field in FunctionSpec? Do you want me to remove this functionality from all except the Native backend for now?

@maleadt
Copy link
Member

maleadt commented Mar 3, 2021

I'm not sure. It's not really a property of the source function, is it? Maybe an extern_policy(::CompilerJob) interface? Aren't the Julia compiler policy (wether to emit symbols or pointers) and the code relocation models two different (if not related) aspects too?

@jpsamaroo
Copy link
Member Author

jpsamaroo commented Mar 3, 2021

I'm not sure. It's not really a property of the source function, is it? Maybe an extern_policy(::CompilerJob) interface?

The reason I shoved static into FunctionSpec is that I assume that imaging mode for GPUCompiler could break some functionality, so I didn't want it enabled globally for any backend until I was sure it worked "perfectly". Nevermind, I misread your comment. Yes, that makes sense to me!

Aren't the Julia compiler policy (wether to emit symbols or pointers) and the code relocation models two different (if not related) aspects too?

I combined these under the assumption that if you're emitting symbols, you probably want to be able to emit relocatable code for shared libraries (since we can actually do that now!). If you want them to be split concepts, how should reloc be specified to llvm_machine?

@jpsamaroo jpsamaroo marked this pull request as ready for review March 4, 2021 00:15
@jpsamaroo
Copy link
Member Author

I setup a few tests, although they won't get run unless you have a recent enough build of Julia. Some of them are skipped because they don't yet work with imaging mode (probably either bugs or missing functionality in Julia), but they should work eventually.

@maleadt
Copy link
Member

maleadt commented Mar 4, 2021

Some of them are skipped because they don't yet work with imaging mode (probably either bugs or missing functionality in Julia), but they should work eventually.

Better make those a @test_broken then so that we get informed when they start passing?

I combined these under the assumption that if you're emitting symbols, you probably want to be able to emit relocatable code for shared libraries (since we can actually do that now!). If you want them to be split concepts, how should reloc be specified to llvm_machine?

Yeah I'm not sure, feel free to keep both aspects linked for now, it's not like GPUCompiler.jl has a stable API or anything 🙂

@jpsamaroo
Copy link
Member Author

jpsamaroo commented Mar 4, 2021

Better make those a @test_broken then so that we get informed when they start passing?

Unfortunately, the thing that's broken is that the IR gets generated just slightly wrong, so we just get a segfault 🙂

Yeah I'm not sure, feel free to keep both aspects linked for now, it's not like GPUCompiler.jl has a stable API or anything slightly_smiling_face

I definitely can separate them in the future, when users end up requesting the ability to differentiate.

@jpsamaroo
Copy link
Member Author

Added an extern flag to the Native target which determines the policy, and left reloc to do exactly what it says.

src/native.jl Outdated Show resolved Hide resolved
test/native.jl Outdated Show resolved Hide resolved
test/native.jl Outdated
@test_skip ccall(generate_shlib_fptr(f5, ()), Symbol, ()) == :asymbol
f6(x) = x == :asymbol ? true : false
@test_skip ccall(generate_shlib_fptr(f6, (Symbol,)), Bool, (Symbol,), :asymbol)
@test_skip !ccall(generate_shlib_fptr(f6, (Symbol,)), Bool, (Symbol,), :bsymbol)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least one of these test should run in an external process.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In reality, anything that relies on runtime calls/state should probably go through another process. I'll spool one up with Distributed and see how far I can get.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach was very enlightening, if also unfortunate. I found that we still emit things like Symbols and some other objects as inttoptr'd pointers. I'm going to have one of the simpler tests run on another process, but clearly there's still some extra work to be done.

@jpsamaroo jpsamaroo marked this pull request as draft June 9, 2021 19:14
@jpsamaroo
Copy link
Member Author

Should I gate Julia global externalization/internalization behind an interface function, or are we okay with keeping it as always-on?

if LLVM.linkage(gbl) == LLVM.API.LLVMInternalLinkage &&
typeof(LLVM.initializer(gbl)) <: LLVM.PointerNull &&
(startswith(LLVM.name(gbl), "jl_global") ||
startswith(LLVM.name(gbl), "jl_sym"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why also jl_sym, not just jl_global (in a function that externalizes globals)?

@maleadt
Copy link
Member

maleadt commented Jun 10, 2021

Should I gate Julia global externalization/internalization behind an interface function, or are we okay with keeping it as always-on?

Do we emit such globals in other scenarios? We're starting to have a lot of interface functions...

@gbaraldi
Copy link
Contributor

gbaraldi commented Jun 2, 2022

@jpsamaroo what was the state of this, I'm thinking of rebasing it since it's the most common error we are hitting right now.

@jpsamaroo
Copy link
Member Author

Aside from this not actually switching on imaging mode (as I pointed out on Slack), I think this mostly was working.

@vchuravy
Copy link
Member

vchuravy commented Jun 3, 2022

I think the issue that this is has is that it doesn't do the processing of the global variables. So you end up with uninitialized GVs and no way to know what's supposed to go in there?

@brenhinkeller
Copy link

Even without global variables, seems like this could be useful for StaticCompiler if it lets us use more of libjulia!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants