# Parsing with custom type JSON3 makes performance worse

**URL:** <https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030>\
**Category:** Performance\
**Created:** [October 20, 2022, 6:38pm UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030 "2022-10-20T18:38:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Robert\_J](https://avatars.discourse-cdn.com/v4/letter/r/58956e/32.png) [@Robert\_J](https://discourse.julialang.org/u/Robert_J)\
**Post date:** [October 20, 2022, 6:38pm UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/1 "2022-10-20T18:38:13Z")

</div>

Here is the sample JSON file:

```julia
"{\"topic\":\"trade.BTCUSDT\",\"data\":[{\"symbol\":\"BTCUSDT\",\"tick_direction\":\"PlusTick\",\"price\":\"19431.00\",\"size\":0.2,\"timestamp\":\"2022-10-18T14:50:20.000Z\",\"trade_time_ms\":\"1666104620275\",\"side\":\"Buy\",\"trade_id\":\"e6be9409-2886-5eb6-bec9-de01e1ec6bf6\",\"is_block_trade\":\"false\"},{\"symbol\":\"BTCUSDT\",\"tick_direction\":\"MinusTick\",\"price\":\"19430.50\",\"size\":1.989,\"timestamp\":\"2022-10-18T14:50:20.000Z\",\"trade_time_ms\":\"1666104620299\",\"side\":\"Sell\",\"trade_id\":\"bb706542-5d3b-5e34-8767-c05ab4df7556\",\"is_block_trade\":\"false\"},{\"symbol\":\"BTCUSDT\",\"tick_direction\":\"ZeroMinusTick\",\"price\":\"19430.50\",\"size\":0.007,\"timestamp\":\"2022-10-18T14:50:20.000Z\",\"trade_time_ms\":\"1666104620314\",\"side\":\"Sell\",\"trade_id\":\"a143da10-3409-5383-b557-b93ceeba4ca8\",\"is_block_trade\":\"false\"},{\"symbol\":\"BTCUSDT\",\"tick_direction\":\"PlusTick\",\"price\":\"19431.00\",\"size\":0.001,\"timestamp\":\"2022-10-18T14:50:20.000Z\",\"trade_time_ms\":\"1666104620327\",\"side\":\"Buy\",\"trade_id\":\"7bae9053-e42b-52bd-92c5-6be8a4283525\",\"is_block_trade\":\"false\"}]}"

```

I was under the impression if I give it a custom type it would make it faster but I was wrong. Here is the defined structure:

```julia
struct Ticket
    symbol::String
    tick_direction::String
    price::String
    size::Float64
    timestamp::String
    trade_time_ms::String
    side::String
    trade_id::String
    is_block_trade::String
end

struct Tape
    topic::String
    data::Vector{Ticket}
end

StructTypes.StructType(::Type{Tape}) = StructTypes.Struct()

```

Now with a simple `JSON3.read(Sample)` I get:

```julia
BenchmarkTools.Trial: 10000 samples with 9 evaluations.
 Range (min … max): 2.897 μs … 1.257 ms ┊ GC (min … max): 0.00% … 99.68%
 Time (median): 3.300 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 4.230 μs ± 29.736 μs ┊ GC (mean ± σ): 18.36% ± 2.63%

  ▃▃▄▇██▇▇▅▄▂▁ ▁▂▁ ▂
  █████████████████▅▃▄▃▆▆▆▅▆▅▆▆▅▆▇▇▇▇▇████▇▇▄▆▅▄▅▆▄▅▃▃▄▄▃▄▄▆ █
  2.9 μs Histogram: log(frequency) by time 6.98 μs <

 Memory estimate: 4.38 KiB, allocs estimate: 7.

```

With the custom type defined `JSON3.read(Sample, Tape)` I get:

```julia
BenchmarkTools.Trial: 10000 samples with 5 evaluations.
 Range (min … max): 6.813 μs … 763.641 μs ┊ GC (min … max): 0.00% … 98.76%
 Time (median): 6.977 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 7.479 μs ± 12.962 μs ┊ GC (mean ± σ): 2.98% ± 1.71%

  ▇█▆▅▂▂▁ ▁▁ ▂
  ████████▇▇█▇█▇█▇▆▆▇████▇▇▅▇▅▇██▇▅▅▅▆▇▅▄▃▅▅▁▁▁▄▁▁▁▁▃▁▄▄▁▄▄▅▄ █
  6.81 μs Histogram: log(frequency) by time 13.5 μs <

 Memory estimate: 3.42 KiB, allocs estimate: 48.

```

Shouldn’t giving hints about the structure of the json file make it more performant? Why Is it regressing?

---

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [October 20, 2022, 10:04pm UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/2 "2022-10-20T22:04:53Z")

</div>

Hmmmm, I wouldn’t expect the typed parsing to be _that_ slow, so maybe something has regressed there in terms of performance. But note that the `JSON3.read(json)` method is pretty heavily optimized and will perform well on nested json compared to a typed case. I’m not sure that completely explains the perf results here since it doesn’t seem _that_ heavily nested, but it might be. If you use the StatProfilerHTML package, we could get flamegraph profiles of the two approaches and see if something seems obviously wrong in the typed case.

---

<div class="post-metadata">

**Author:** ![Robert\_J](https://avatars.discourse-cdn.com/v4/letter/r/58956e/32.png) [@Robert\_J](https://discourse.julialang.org/u/Robert_J)\
**Post date:** [October 21, 2022, 9:12am UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/3 "2022-10-21T09:12:26Z")

</div>

Here is the simple JSON3.read :

 ![Screen Shot 2022-10-21 at 12.40.49 PM](https://global.discourse-cdn.com/julialang/original/3X/f/b/fb76624c142c8cc6c802e8fe8595f05d47528530.png)

And here is the typed version:

 ![Screen Shot 2022-10-21 at 12.41.46 PM](https://global.discourse-cdn.com/julialang/original/3X/3/0/30e8f38d07d9b64ab414483450dbfa63378c87ed.png)

I wrapped them in a function to repeat multiple times for the profiler to pick up.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 21, 2022, 10:57am UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/4 "2022-10-21T10:57:52Z")

</div>

Looks like it is just looking up a large number of symbols. A symbol is an interned string and when looking them up you have to look through all the symbols that exist in the Julia session. There are probably some quite easy optimizations that can be made, like having a local `Dict{String, Symbol}` or just never materializing the symbol at all.

---

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [October 21, 2022, 5:44pm UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/5 "2022-10-21T17:44:55Z")

</div>

Very helpful thank you. Yes, as @kristoffer.carlsson mentioned, it looks like there’s room for optimization here. Would you mind opening an issue on the JSON3.jl repo and I’ll try to take a look at improving things?

---

<div class="post-metadata">

**Author:** ![Robert\_J](https://avatars.discourse-cdn.com/v4/letter/r/58956e/32.png) [@Robert\_J](https://discourse.julialang.org/u/Robert_J)\
**Post date:** [October 21, 2022, 8:04pm UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/6 "2022-10-21T20:04:32Z")

</div>

Yeah no problem, I’ll open one.

> [@kristoffer.carlsson](#):
>
> like having a local `Dict{String, Symbol}`

Thanks for the repIy. I am a little inexperienced so sorry for the noob question. I searched and got more confuse, How can I implement this, is it something that should be done inside the JSON3 package? If you point to some sample code out there I’ll be very thankful.

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [October 21, 2022, 8:56pm UTC](https://discourse.julialang.org/t/parsing-with-custom-type-json3-makes-performance-worse/89030/7 "2022-10-21T20:56:57Z")

</div>

> [@kristoffer.carlsson](#):
>
> A symbol is an interned string and when looking them up you have to look through all the symbols that exist in the Julia session.

Wait what, does Julia not have a Dict of Symbols? Why not?
