Can I define a precompile sequence?


#1

I find it a bit difficult to figure out how to use the precompile system properly. Documentation appears to be sparse.

A few months ago @tim.holy made an interesting post on my Github page:
-> https://github.com/ma-laforge/InspectDR.jl/issues/1

He indicated that Julia will not generate machine code with the following unless I explicitly include the precompile(bar, (Float64,)) statement:

__precompile__()

module CC

bar(x::Float64) = 2x

precompile(bar, (Float64,))

end

I was surprised, because I assumed Julia would always precompile functions down to machine code when all arguments were concrete. However, I was able to confirm his statement: Indeed mul_float only appeared in CC.ji if I explicitly called precompile(...).

My experience with SnoopCompile.jl
I find it a bit difficult to use correctly - mostly because I don’t really understand how the precompile system works. It also seems like more complex packages require a fair amount of manual intervention for things to work smoothly.

So I thought of the following:
What if, instead, you defined a function that exercised the code you wish to pre-compile directly in your module?

That way, you could trigger the compilation of lower-level functions without having to explicitly add an entry for each one:

__precompile__()

module CC

bar(x::Float64) = 2x

function precompile_sequence()
	#Trigger compilation of lower-level functions by exercising high level functions:
	bar(2.0) #A simple test

	#Add some high-level functions that exercise the user code here.
	#Maybe execute some of the built-in tests?

	return nothing
end

precompile(precompile_sequence, ())

end

This way, I don’t have to generate entries for each function I wish to precompile… as long as I can trigger a chain of calls that does this for me. I guess this is sort of how SnoopCompile.jl works… but without going through intermediate files, etc.

Would this work? Does anybody see issues with this methodology? It can be somewhat difficult to tell if I am using the precompile system correctly.


#2

Currently the precompilation never include machine code.[quote=“MA_Laforge, post:1, topic:2474”]
This way, I don’t have to generate entries for each function I wish to precompile… as long as I can trigger a chain of calls that does this for me
[/quote]

The precompilation should already be recursive. If you prefer to organize this way (i.e. call the function with arguments rather than specifying the type, you can certainly do so.)


#3

Note that for simplicity you can just do

bar(1.0)

to precompile bar with a Float64 argument. I usually just have a “precompile.jl” file that contains lines like this, with no need to call the precompile function.


#4

Thanks for the answers/suggestions.

I just can’t seem to get things to go much faster despite trying to add my test code in a precompile function.

It still takes ~10s to run my test code… whether or not that code is included in a precompile function.

(it only takes ~0.2s to re-run that test code after the first execution).

I tried hacking in a similar pre-compile function to Gtk.jl (trying to precompile the creation of windows, menu bars, grid objects, etc) but first execution is still within the noise of ~10s.

I suppose the problem might just be that I would need to hack in precompilations for functions in the entire dependency tree… but I don’t see myself doing that at this point (at least not for a package that depends on 17 others).

Maybe the precompile system will get better… or maybe I can figure out a better way to use it later on…