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

precompile fails to cache code for calls that are not fully specialized (non-concrete signature) #46778

Closed
KristofferC opened this issue Sep 15, 2022 · 2 comments · Fixed by #47259
Assignees
Labels
compiler:precompilation Precompilation of modules

Comments

@KristofferC
Copy link
Member

In #46690, I want to deserialize an object on a precompile worker and it is quite important that this is fully precompiled since a lot of precompile workers are spawned and each of these have a separate process and thus they would all need to compile the same code over and over if this isn't the case.

For arbitrary data types, deserialize has a function that takes ::DataType and will not get specialized:

function deserialize(s::AbstractSerializer, t::DataType)

As an example workload we can look at the following code

using Serialization

struct MyStruct
    x::String
end

s = MyStruct("foo")

io = IOBuffer()
serialize(io, s)
seekstart(io)
@time deserialize(io);

Running that with --trace-compile=stderr the following precompile statements are emitted from the deserialize call:

precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.GenericIOBuffer{Array{UInt8, 1}}}, DataType})

However, restarting Julia and executing these before the deserialize call we can see that the precompile call for the DataType fails:

julia> precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.IOStream}, DataType})
false

and the compilation time is still there.

However, if we specialize the function on the data type (as done in 6e0b2da#diff-0fbb91f060d958d93fcf0a101ade4d87b365f3664a409276c591d7faf77acb67) the precompilation statements we get is:

precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.GenericIOBuffer{Array{UInt8, 1}}}, Type{Main.MyStruct}})

the compilation time is then removed:

julia> @time deserialize(io);
  0.000014 seconds (14 allocations: 1.148 KiB)

It would be good if the code that is compiled for signatures that are non-concrete could be cached. They clearly are when you run the code since you don't have to compile it for every call.

@timholy
Copy link
Member

timholy commented Sep 15, 2022

What happens if you explicitly add @nospecialize(t::DataType)?

@KristofferC
Copy link
Member Author

KristofferC commented Sep 15, 2022

That doesn't seem to change anything (running with --trace-compile=stderr):

julia> precompile(Tuple{typeof(Serialization.deserialize), Base.GenericIOBuffer{Array{UInt8, 1}}})
precompile(Tuple{typeof(Serialization.deserialize), Base.GenericIOBuffer{Array{UInt8, 1}}})
true

julia> precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.GenericIOBuffer{Array{UInt8, 1}}}, DataType})
false

julia> @time deserialize(io);
precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.GenericIOBuffer{Array{UInt8, 1}}}, DataType})
  0.013337 seconds (15.33 k allocations: 1011.251 KiB, 98.18% compilation time)

You can see, the precompile statement for the DataType one is printed again, showing how it failed to cache the one from the explicit precompile call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:precompilation Precompilation of modules
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants