3Hren / msgpack-rust

MessagePack implementation for Rust / msgpack.org[Rust]
MIT License
1.17k stars 130 forks source link

Improve the deserializer compile time #350

Open s-nie opened 3 months ago

s-nie commented 3 months ago

I noticed that using rmp_serde to deserialize large structs has a considerable effect on the compile time. It also has twice the impact of comparable crates like serde_json when generating deserialization code.

The solution here is to take as much code as possible out of generic methods that are instantiated for each type. This reduces the LLVM IR lines from 3652241 to 3238664 (-11.3%) and the time to compile rmp_serde::from_slice::<MyBigStruct>(&[]) from 52s to 33s (-36%). For reference, doing the same with serde_json takes about 25s to compile.

Here are the LLVM stats of the worst offenders before and after the changes. any_inner is still pretty high up and with some more elbow grease it might be possible to reduce it more, but I don't feel comfortable going any further in this PR.

before

  Lines                  Copies               Function name
  -----                  ------               -------------
  3652241                71401                (TOTAL)
   350636 (9.6%,  9.6%)    331 (0.5%,  0.5%)  rmp_serde::decode::Deserializer<R,C>::any_inner
   256153 (7.0%, 16.6%)    339 (0.5%,  0.9%)  rmp_serde::decode::any_num
   253829 (6.9%, 23.6%)    302 (0.4%,  1.4%)  <serde_value::de::ValueDeserializer<E> as serde::de::Deserializer>::deserialize_any
   174191 (4.8%, 28.3%)    935 (1.3%,  2.7%)  serde::de::Visitor::visit_byte_buf
   150146 (4.1%, 32.4%)    263 (0.4%,  3.0%)  <serde_value::de::ValueDeserializer<E> as serde::de::Deserializer>::deserialize_struct
   102226 (2.8%, 35.2%)    399 (0.6%,  3.6%)  <serde_value::de::ValueDeserializer<E> as serde::de::Deserializer>::deserialize_identifier
    69688 (1.9%, 37.2%)   1218 (1.7%,  5.3%)  core::result::Result<T,E>::map_err
    63733 (1.7%, 38.9%)    331 (0.5%,  5.8%)  rmp_serde::decode::read_str_data
    55013 (1.5%, 40.4%)    755 (1.1%,  6.8%)  <serde::de::value::SeqDeserializer<I,E> as serde::de::SeqAccess>::next_element_seed
    34399 (0.9%, 41.3%)    400 (0.6%,  7.4%)  <serde::de::value::MapDeserializer<I,E> as serde::de::MapAccess>::next_key_seed
    30805 (0.8%, 42.2%)    906 (1.3%,  8.7%)  <T as erased_serde::ser::Serialize>::do_erased_serialize
    27173 (0.7%, 42.9%)   1268 (1.8%, 10.4%)  serde::de::Visitor::visit_newtype_struct

after

  Lines                  Copies               Function name
  -----                  ------               -------------
  3238664                71407                (TOTAL)
   253829 (7.8%,  7.8%)    302 (0.4%,  0.4%)  <serde_value::de::ValueDeserializer<E> as serde::de::Deserializer>::deserialize_any
   175446 (5.4%, 13.3%)    331 (0.5%,  0.9%)  rmp_serde::decode::Deserializer<R,C>::any_inner
   174191 (5.4%, 18.6%)    935 (1.3%,  2.2%)  serde::de::Visitor::visit_byte_buf
   150146 (4.6%, 23.3%)    263 (0.4%,  2.6%)  <serde_value::de::ValueDeserializer<E> as serde::de::Deserializer>::deserialize_struct
   102226 (3.2%, 26.4%)    399 (0.6%,  3.1%)  <serde_value::de::ValueDeserializer<E> as serde::de::Deserializer>::deserialize_identifier
    69558 (2.1%, 28.6%)   1214 (1.7%,  4.8%)  core::result::Result<T,E>::map_err
    55013 (1.7%, 30.3%)    755 (1.1%,  5.9%)  <serde::de::value::SeqDeserializer<I,E> as serde::de::SeqAccess>::next_element_seed
    53908 (1.7%, 31.9%)    339 (0.5%,  6.4%)  rmp_serde::decode::any_num
    34399 (1.1%, 33.0%)    400 (0.6%,  6.9%)  <serde::de::value::MapDeserializer<I,E> as serde::de::MapAccess>::next_key_seed
    32777 (1.0%, 34.0%)    331 (0.5%,  7.4%)  rmp_serde::decode::visit_str_data
    30805 (1.0%, 35.0%)    906 (1.3%,  8.6%)  <T as erased_serde::ser::Serialize>::do_erased_serialize
    27173 (0.8%, 35.8%)   1268 (1.8%, 10.4%)  serde::de::Visitor::visit_newtype_struct