In short it’s faster, should go down to 1.02 sec from 1.318, 23% faster, assuming precompile overhead 0.51+ sec goes away, to run the abstract syntax tree (AST) than parse a script. I was testing with:
However it’s not currently because (i.e. would be if deserialize were in the sysimage, assuming it doesn’t slow down startup much):
$ julia +1.13 --trace-compile=stderr -e "using Serialization; forms = deserialize(\"input.jast\")"
precompile(Tuple{typeof(Serialization.deserialize), String})
precompile(Tuple{typeof(Serialization.deserialize_fillarray!), Array{Any, 1}, Serialization.Serializer{Base.IOStream}})
precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.IOStream}, typeof(DataType)})
$ hyperfine 'julia +1.13 -e "using Serialization; forms = deserialize(\"input.jast\")" >/dev/null'
708.8-191.2 = 517.6 ms after accounting for startup. 1.318
But deserialize only costs 0.3935 ms (2821-212.8)/10000 = 0.26 ms on Julia 1.14, and timed with more accurate 10,000 iterations, for my example code (35% faster than parsing the code, if I recall). Because of the precomilation overhead it’s much more now, shown by:
$ hyperfine 'julia/julia -e "using Serialization; for i in 1:10000 forms = deserialize(\"input.jast\") end" '
Benchmark 1: julia/julia -e "using Serialization; for i in 1:10000 forms = deserialize(\"input.jast\") end"
Time (mean ± σ): 2.927 s ± 0.082 s [User: 2.726 s, System: 0.194 s]
Range (min … max): 2.810 s … 3.052 s 10 runs
$ hyperfine 'julia +1.13 -e "using Serialization; for i in 1:1000 forms = deserialize(\"input.jast\") end" '
Benchmark 1: julia +1.13 -e "using Serialization; for i in 1:1000 forms = deserialize(\"input.jast\") end"
Time (mean ± σ): 1.201 s ± 0.076 s [User: 1.058 s, System: 0.141 s]
Range (min … max): 1.104 s … 1.328 s 10 runs
So are we willing to have deserialize in the sysimage?
Currently 0.508 sec slower (only 1.530-1.318 = 0.21 sec slower on Julia 1.14, much better then the 0.51 sec precompilation overhead on 1.14) than running directly:
$ hyperfine "julia +1.13 -e 'using Serialization; forms = deserialize(\"input.jast\"); foreach(eval, forms);' 25000000 >/dev/null"
$ hyperfine "julia +1.13 fasta2.jl 25000000 >/dev/null"
using Serialization
filename = "fasta2.jl"
src = read(filename, String)
forms = Any[]
pos = 1
while pos <= lastindex(src)
ex, nextpos = Meta.parse(src, pos; raise=false, filename=filename)
ex === nothing && break
push!(forms, ex)
nextpos <= pos && break
pos = nextpos
end
open("input.jast", "w") do io
serialize(io, forms)
end
I got more precompiles on 1.14, running separately:
julia> using Serialization
julia> @time precompile(Tuple{typeof(Base.ScopedValues.hasdefault), Base.ScopedValues.ScopedValue{Union{Nothing, Module}}})
0.001457 seconds (1.65 k allocations: 80.516 KiB, 97.14% compilation time)
julia> @time precompile(Tuple{typeof(Base.ScopedValues.getdefault), Base.ScopedValues.ScopedValue{Union{Nothing, Module}}})
0.002533 seconds (2.58 k allocations: 126.953 KiB, 97.56% compilation time)
julia> @time precompile(Tuple{Core.TypeEgal{Base.Fix{1, F, T} where T where F}, typeof(Base.ScopedValues.getdefault), Base.ScopedValues.ScopedValue{Union{Nothing, Module}}})
0.001903 seconds (1.38 k allocations: 75.141 KiB, 95.06% compilation time)
julia> @time precompile(Tuple{Base.Fix{1, typeof(Base.ScopedValues.getdefault), Base.ScopedValues.ScopedValue{Union{Nothing, Module}}}})
0.004907 seconds (8.37 k allocations: 415.836 KiB, 98.68% compilation time)
julia> @time precompile(Tuple{typeof(Serialization.deserialize), String})
**0.510236** seconds (436.34 k allocations: 23.950 MiB, 6.44% gc time, 99.99% compilation time)
julia> @time precompile(Tuple{typeof(Serialization.deserialize_fillarray!), Array{Any, 1}, Serialization.Serializer{Base.IOStream}})
0.002802 seconds (4.28 k allocations: 230.438 KiB, 98.47% compilation time)
julia> @time precompile(Tuple{typeof(Serialization.deserialize), Serialization.Serializer{Base.IOStream}, Core.TypeEgal{LineNumberNode}})
0.046021 seconds (13.89 k allocations: 800.102 KiB, 99.90% compilation time)
julia> @time precompile(Tuple{typeof(Base.foreach), Core.EvalInto, Array{Any, 1}})
0.003172 seconds (2.59 k allocations: 149.766 KiB, 98.61% compilation time)
julia> @time precompile(Tuple{Core.TypeEgal{Ref{T} where T}, UInt32})
0.001111 seconds (704 allocations: 34.969 KiB, 94.53% compilation time)
julia> @time precompile(Tuple{typeof(Base.rem), Char, Core.TypeEgal{UInt8}})
0.001404 seconds (256 allocations: 11.781 KiB, 96.56% compilation time)
julia> @time precompile(Tuple{typeof(Base.convert), Core.TypeEgal{Tuple{Vararg{Int64}}}, Tuple{Int32}})
0.001155 seconds (65 allocations: 3.375 KiB, 91.74% compilation time)
julia> @time precompile(Tuple{typeof(Base.:(-)), Int32, Int64})
0.001469 seconds (51 allocations: 2.891 KiB, 93.78% compilation time)
julia> @time precompile(Tuple{typeof(Base.:(/)), Int64, Int32})
0.001248 seconds (978 allocations: 48.484 KiB, 94.51% compilation time)