-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
static compile part 6: automated opt-in compilation #12462
Comments
i did this for some time in the original #8745 PR. (at the time, I was also passing the parsed version directly to
another option is to couple this step to the Pkg manager, so that Pkg.add / Pkg.update / Pkg.checkout / etc will manage some metadata for whether to call Base.compile. Arguably, this would make |
As for package manager, it should not be a problem to put a compilation step after package update, somewhere here. |
Magic comments (I like Yes, a |
Or extend a package description, #11955. I would see it as a part of requirements description in REQUIRE file rather then a separate empty file. You would need to touch |
@wildart, I disagree with the notion of using the package manager to manage _re_compilation; I think it would be brittle and inflexible (e.g. it wouldn't recompile when a developer is hacking on the package, or when you install a new Julia version). But if you want to talk about recompilation strategy, please go to #12259 ... this issue is about opting in for the initial compilation. Obviously, if the structure of the package metadata changes, where you would put the compilation opt-in would change. But since I doubt #11955 will be resolved in time for 0.4, I would prefer not to rely on it here. |
I would think of opt-out option rather then opt-in. Disabling static compilation for modules or functions looks more reasonable then any opt-in options. Don't we want to compile everything? Wouldn't a faster code loading improve user experience? |
There are definitely packages that won't work if compiled. http://docs.julialang.org/en/latest/manual/modules/#module-initialization-and-precompilation |
I confess I kind of like the magic comment, too. As someone who has ~100 "packages" not managed by the package manager (i.e., lab-specific code), I'm a little less excited about coupling this to the package manager (but will cope if this is the outcome). |
+1 for not tying this to the package manager. also +1 for making this opt-out: in my work on SystemImageBuilder.jl I found only few packages (of the 60+ I use) that can't be precompiled. My suggestion would be: module MyModule
#pragma nocompile
... In a concerted effort we can quickly add this to the packages which can't be precompiled (yet), and it adds an incentive to actually make those packages precompilable. |
I think most packages are compilable, so the opt-out pragma would be better. |
Julia is a safe language by default, and making this opt-out would violate that contract and totally change the spirit of the language. Compilation has to be for people who know what they are doing; otherwise, this is a deathtrap for new developers. |
@bicycle1885, the fact that a macro requires parsing is a big disadvantage. This is a classic use for a pragma directive, because it is effectively a compiler option rather than part of the language per se. |
(A long opt-in vs. opt-out discussion already took place in #8745.) |
Ah OK. Comment works for me. |
I see. Safe-default principle makes sense to me. I think the pragma should take an argument (for example, #pragma compile yes
#pragma compile no |
Unfortunately, I missed first "opt-in vs opt-out" but I have a feeling that as soon as 0.4 will be released every package developer will put |
…when a module is required (closes JuliaLang#12462)
…when a module is required (closes JuliaLang#12462)
Eww, -1 to significant comments. Comments are for humans, and get thrown away pretty early in the Julia parsing-to-execution pipeline. |
…when a module is required (closes JuliaLang#12462)
@tkelman, the whole point of a pragma is that it occurs before the parsing-to-execution pipeline, and it is not part of the language per se — it is a compiler hint. Also, all the alternatives seem worse. |
So far most of the ways of interacting with the Julia compiler have been part of the language - it feels wrong to suddenly buck that trend. And pretty much all Julia code, with the exception of comments, has usually been treated equally whether it came from a program or a file.
|
(Basically this means that every non-compilable module would get parsed twice every single time it is loaded: once to check for Also, see @vtjnash's comment above: the compiler is technically per-file (it compiles every module in a file), not per-module, so |
I think we either need to do #7449 or rely on Compat here. If we want #7449 to look like If we're also planning on a much shorter 0.5 release, then maybe it won't be as bad either. |
Would it make sense to put compilation opt-in into METADATA? |
@quinnj, the problem with relying on Compat is that Compat is included inside the module, and here we need something outside. See also the problems with double-parsing, and per-module rather than per-file semantics. |
I don't think compilability is significant enough to warrant a different file extension. Unless perhaps this veers off into, say, a statically-typed variant of the language. |
@ScottPJones, there is still a problem with the short-circuiting |
Why would it barf at the |
@ScottPJones, because |
but wouldn't it only short-circuit parse/eval of |
Another thing, can the Julia compiler always correctly determine if something is "compilable" or not? |
@ScottPJones, no, because it can't finish evaluating Foo if a module it depends on barfs on And no, it can't determine automatically whether a module is (safely) compilable. (It can compile anything, but modules that don't follow certain rules will get compiled to incorrect code.) That's why it has to be a human opt-in. |
Somewhere in between, but single-module is a bit better. There's still quite a lot of mix-and-match going on. |
@tkelman,
plus magic not-quite-julia parse-without-eval interpretation at |
We haven't done a sufficiently good job of emulating bash's outstanding syntax choices. So I'm all in favor of |
|
@stevengj I guess I just don't understand.
I also think that compilers are much better than humans usually in determining if code is "following the rules". Where are all the rules that need to be followed? |
… a module is required (closes JuliaLang#12462)
@ScottPJones, the problem is the "parse/evaluate the file, see if it is cacheable" step. That's what we're discussing here. A long discussion of why compilability can't be determined automatically already occurred in #8745, and the rules are described in the precompiling section of the manual. |
Tomorrow, I'll try to put together an alternative PR based on @ScottPJones's short-circuit |
OK, so you can still do as I've outlined above, but instead of being able to determine cacheability automatically (I had missed all of the old conversation, I'll have to read it tomorrow), it could just use What other problems do you see with that technique? It avoids looking at the source code, even to do a regex, if the .ji file is present and valid, if it the .ji file says that it is not cacheable, it just does what it has always done, i.e. parse/eval the file. |
That would be great, thanks for having patience with a sleep deprived old PITA! |
@ScottPJones, it's just that the |
OK, I hadn't looked at the |
i think the key is that compilation of a module always occurs in a separate process, and never as a side effect of running code in the local instance I added a number of examples of failure cases to the end of the Modules documentation: Note that Of those, I expect that #12010 may be the most serious and limiting. The others hopefully are fairly benign and expected. There are a few classes of failure scenarios that are pretty easy for the compiler to detect and complain about (and so it already does). Most of the others are broken only by determining the author's actual intent. There are many valid reasons to alter global state while compiling a module (reading files, opening libraries, creating counters, and manipulating shared structures like LOAD_PATH and ARGS), which makes it impossible for the compiler to guess at the user's intent. For example, given the following script, what should the runtime value of
There are two choices:
parsing the file is a pretty negligible cost, but if you want to avoid doing it twice, but still wanted to have the benefits of parsed code, one option is to note that Line 276 in b78659e
In past versions of the code, this function actually just took an Expr (although, to be fair, in the past versions of the code, it only accepted a Expr(:module) )
|
…pilation on import (closes JuliaLang#12462)
…pilation on import (closes JuliaLang#12462)
Okay, no macro required, and no magic non-Julia syntax. Just |
Cool! I hope this satisfies @tkelman's objections (it does mine). Great stuff no matter what the syntax, Steve! |
@vtjnash It is true that the compile/run time distinction is unclear right now. To be honest, I feel that for the next release we should aim at making it more explicit. I don't think the goal should be to try to transparently cache module and pretend that Instead, maybe we could have a Something like that ? module Foo
const runtime_v = Base.VERSION
cached
const compiled_v = Base.VERSION
end
end I didn't think this through but I believe my general point stands : we should not be scared of changing module semantic to make this feature first class, instead of this "dangerous but everyone will still use it because load times are unbearable". As for rehashing, it may be hairy to make it work but maybe we should use the julia serializer at least for user types to let them handle this ? |
…pilation on import (closes JuliaLang#12462)
(another disadvantage of the |
Given automated recompilation (#12259, hopefully coming soon via #12458), it would be good to eliminate the manual call to
Base.compile
for most users, which is both awkward and dangerous (since users won't know whether a module is compilable). I think we want a way for a module author to mark it as compilable so thatusing Foo
will automatically callBase.compile
if it has not been compiled yet.It will be easy to implement this, once we decide on a syntax. Some options:
#@compilable
#pragma compilable
) at the top of the file. Pro: backwards compatible with Julia 0.3, easy to check before parse andeval
of the file, is per-file like compilation, simple and robust to implement (add "#pragma compile [true]" for opt-in to automatic compilation #12475). Con: not very Julian.@compilable module Foo ... end
: Pro: more Julian, can be checked after parsing but beforeeval
. Con: hard to make backwards-compatible (a major problem), requires parsing (non-compiled files will be parsed twice every time they are included!), and per-module rather than per file.@compilable
statement inside the module. Pro: can be made backward-compatible via Compat. Con: must eval the module to execute it, which means that if it is compiled too then it gets evalled twice, and the compiled version is not the one that is loaded (since it has already been imported), and is per-module whereas compilation is per-file.Updates:
Pkg
: e.g. aCOMPILABLE
file in the package directory would cause the package to be compiled when it is added (automated recompilation could handle the rest). Pro: backward compatible, no parse/eval. Con: auto-compilation only available for registered packages, does not allow compilation to be disabled for a module unlessBase.compile
hooks intoPkg
.@compilable; module Foo ... end
: as@compilable module
but per file, otherwise same pros and cons.Any other options? I have to admit that I lean toward the magic comment, since avoiding parse/eval is attractive enough to me to compensate for the slight syntactical ugliness.
The text was updated successfully, but these errors were encountered: