Hi,
I’m trying to create an application to distribute, this application is loading a JSON configuration file. Since I wanted a one to one binding between the application data and the JSON I’m using the JSON3 package.
Here is my performance test for serialization and deserialization
using TestJson.Models
using Test
objects = [
AppleData(Vector3D(10.0, 5.0, 3.0)),
CarData(Vector3D(7.0, 0.0, 0.0))
]
s = SceneData(objects)
# Call the serialize
json = serialize(s, true)
println(json)
# Encapsulate time into a function
time_deserialize(x) = @time deserialize(x, SceneData)
# Call the deserialize
s1 = time_deserialize(json)
println(s1)
The output is here :
{
"name": "Default Scene",
"objects": [
{
"type": "apple",
"position": {
"x": 10,
"y": 5,
"z": 3
},
"weight": 0.1
},
{
"type": "car",
"position": {
"x": 7,
"y": 0,
"z": 0
},
"weight": 1000,
"model": "Julia model S",
"electric": false
}
]
}
5.498082 seconds (2.20 M allocations: 127.961 MiB, 0.80% gc time, 99.99% compilation time)
SceneData("Default Scene", AbstractObject[AppleData("apple", [10.0, 5.0, 3.0], 0.1), CarData("car", [7.0, 0.0, 0.0], 1000.0, "Julia model S", false)])
So it’s taking 5 seconds to convert the string to the SceneData, I noticed that the compilation time is 99% of the runtime, so I guess something is not defined for some types.
However I fill like, I’ve not yet the expertise to understand which type are not resolve here, and how could I precompile every variant so the first execution is quicker.
Here are all the models I’m using into this example:
########## AbstractObject.jl ###############
using StructTypes
abstract type AbstractObject end
StructTypes.StructType(::Type{AbstractObject}) = StructTypes.AbstractType()
StructTypes.subtypekey(::Type{AbstractObject}) = :type
############### Apple.jl ###############
using JSON3
struct AppleData <: AbstractObject
type::String
position::Vector3D
weight::Float64
end
AppleData(position::Vector3D) = AppleData("apple", position, 0.1)
JSON3.StructType(::Type{AppleData}) = JSON3.Struct()
############### Car.jl ###############
using JSON3
struct CarData <: AbstractObject
type::String
position::Vector3D
weight::Float64
model::String
electric::Bool
end
CarData(position::Vector3D) = CarData("car", position, 1000, "Julia model S", false)
JSON3.StructType(::Type{CarData}) = JSON3.Struct()
############### Vector3D.jl ###############
using StructTypes
using StaticArrays
struct Vector3D <: FieldVector{3, Float64}
x::Float64
y::Float64
z::Float64
end
Vector3D() = Vector3D(0.0, 0.0, 0.0)
StructTypes.StructType(::Type{Vector3D}) = StructTypes.Struct()
############### SceneData.jl ###############
using JSON3
struct SceneData
name::String
objects::Vector{AbstractObject}
end
SceneData(objects::Vector{AbstractObject}) = SceneData("Default Scene", objects)
JSON3.StructType(::Type{SceneData}) = JSON3.Struct()
Then I define all JSON3 AbstractObject supported types like this :
# Defining supported object type
StructTypes.subtypes(::Type{AbstractObject}) = (
apple=AppleData,
car=CarData
)
Here are the serialize and deserialize functions:
# serialize data to string (quick enough)
function serialize(data, pretty::Bool=false)::String
if (pretty)
io = IOBuffer()
JSON3.pretty(io, data)
String(take!(io))
else
JSON3.write(data)
end
end
# deserialize a string to proper struct - Way to slow
function deserialize(json_data::String, ::Type{T})::T where {T}
JSON3.read(json_data, T)
end
Finally I try to precompile the deserialize function for SceneData like so :
precompile(deserialize, (String, SceneData))
Everything is define into a package TestJson with include a module TestJson.Models which contain every struct definition.
If someone have some lead for me to optimize the first call of the deserialize it would help a lot !
This is actually a very simple version of what kind of object structures I want to support in my application. Actually with a full configuration, it take up to 30 seconds the first execution, and since the configuration is loaded only once at the startup, it is really an issue because subsequent call of deserialize will not happen later.
Hope this concrete example can help me learn more about julia performance, and maybe some of you will be able to see obvious mistake in this implementation