Skip to content
This repository was archived by the owner on Aug 15, 2021. It is now read-only.
This repository was archived by the owner on Aug 15, 2021. It is now read-only.

Compilation is very slow, especially for release builds #189

Description

@Timmmm

The example file below contains a load of serde-derive'd structs and code to load them using serde_cbor. I compiled it in release & debug, and then again after changing serde_cbor to serde_json to get the following compile times:

Debug Release
serde_json 5.0s 13.3s
serde_cbor 11.2s 53.9s

As you can see it is a lot slower than serde_json, and the release build is unusably slow. By looking at the Rust and LLVM profiling outputs I found that most of the time is spent in LLVM and mostly in optimising serde_cbor-related functions.

I compared the output of cargo expand and as expected the only line that changes is serde_cbor/json::from_reader().

To get the LLVM timings run this command:

cargo +nightly rustc --release -- -Zself-profile -Zno-parallel-llvm -Zllvm-time-trace

And then open the resulting llvm_timings.json in about:tracing.

image

If you zoom in and click on the OptFunction blocks it tells you which function it is optimising.

image

From clicking around randomly the most common one is serde_cbor::de::Deserializer<R>::parse_value function (with various hashes at the end), but there's also parse_str, parse_map, recursion_checked, etc. Kind of makes sense because parse_value has that big map but honesty I can't see why it should take so long.

Here's my test code:

#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

use serde::Deserialize;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use anyhow::Result;

#[derive(Deserialize, Debug)]
pub struct CA {
  pub a: CB,
  pub b: CC,
  pub c: HashMap<String, f64>,
  pub d: Vec<CD>,

  pub e: CE,
  pub f: CF,

  pub g: Vec<CG>,
  pub h: Vec<u32>,
  pub i: Vec<u32>,

  pub j: CJ,
  pub k: CH,
  pub l: CL,

  pub n: Memory,

  pub o: Option<CO>,
}

#[derive(Deserialize, Debug)]
pub struct CO {
  pub a: String,
  pub b: String,
  pub c: u32,
  pub d: u32,
  pub e: u32,
}

#[derive(Deserialize, Debug)]
pub struct CB {
  pub a: u64,
  pub b: u64,
  pub c: u64,
  pub d: u64,
}

#[derive(Deserialize, Debug)]
pub struct CD {
  pub a: String,
  pub b: u64,
  pub c: String,
  pub d: String,
  pub e: u32,
  pub f: u32,
  pub g: u64,
}

#[derive(Deserialize, Debug)]
pub struct CJ {
  pub a: Vec<Vec<u64>>,
  pub b: Vec<Vec<u64>>,
  pub c: Option<Vec<Vec<u64>>>,
  pub d: Vec<Vec<u64>>,
  pub e: Option<Vec<String>>,
  pub f: Option<Vec<String>>,

}

#[derive(Deserialize, Debug)]
pub struct CL {
  pub a: Vec<Vec<u64>>,
  pub b: Vec<Vec<u64>>,
  pub c: Vec<Vec<u64>>,
  pub d: Option<Vec<HashMap<String, String>>>,
  pub e: Option<Vec<HashMap<String, String>>>,

}

#[derive(Deserialize, Debug)]
pub struct CH {
  pub a: Vec<Vec<u64>>,
  pub b: Vec<Vec<u64>>,
  pub c: Vec<Vec<u64>>,
  pub d: Option<Vec<String>>,
  pub e: Option<Vec<String>>,

}

#[derive(Deserialize, Debug)]
pub struct CE {
  pub a: Vec<String>,
  pub b: Vec<Vec<u32>>,
  pub c: Vec<Vec<u32>>,
  pub d: Option<CycleEstimates>,
}

#[derive(Deserialize, Debug)]
pub struct CycleEstimates {
  pub a: Vec<Vec<u64>>,
  pub b: Vec<Vec<u64>>,
  pub c: Vec<Vec<u64>>,
}

#[derive(Deserialize, Debug)]
pub struct CC {
  pub a: u64,
  pub b: u64,
  pub c: f64,
  pub d: u64,
  pub e: u64,
  pub f: u64,
  pub g: Vec<u64>,
  pub h: u64,
  pub i: u64,
  pub j: TT,
}

#[derive(Deserialize, Debug)]
pub enum TT {
  A,
  B,
  C,
}

#[derive(Deserialize, Debug)]
pub struct CF {
  pub a: Vec<String>,
  pub b: Vec<u64>,
}

#[derive(Deserialize, Debug)]
pub struct Memory {
  pub a: DA,
  pub b: DB,
  pub c: DC,
  pub d: DD,
  pub e: DE,
}

#[derive(Deserialize, Debug)]
pub struct DA {
  pub a1: AA,
  pub a2: AA,
  pub a3: AA,
  pub a4: AA,
  pub a5: AA,
  pub a6: AA,
  pub a7: AA,
  pub a8: AA,
  pub a9: AA,
  pub a10: AA,
  pub a11: AA,
  pub a12: AA,
  pub a13: AA,
  pub a14: AA,
  pub a15: AA,
  pub a16: AA,
  pub a17: AA,
  pub a18: AA,
  pub a19: AA,
  pub a20: AA,
  pub a21: AA,
  pub a22: AA,
}

#[derive(Deserialize, Debug)]
pub struct AA {
  pub a: XS,
  pub b: XS,
  pub c: XS,
  pub d: Vec<u32>,
}

#[derive(Deserialize, Debug)]
pub struct XS {
  pub a: Vec<u32>,
  pub b: Vec<u32>,
}

#[derive(Deserialize, Debug)]
pub struct DB {
  pub a1: Vec<Vec<u32>>,
  pub a2: Vec<Vec<u32>>,
  pub a3: Vec<Vec<u32>>,
  pub a4: Vec<Vec<u32>>,
  pub a5: Vec<Vec<u32>>,
  pub a6: Vec<Vec<u32>>,
  pub a7: Vec<Vec<u32>>,
  pub a8: Vec<Vec<u32>>,
}

#[derive(Deserialize, Debug)]
pub struct DC {
  pub a1: Vec<u32>,
  pub a2: Vec<u32>,
  pub a3: Vec<u32>,
  pub a4: Vec<u32>,
  pub a5: Vec<u32>,
  pub a6: Vec<u32>,
  pub a7: Vec<u32>,
  pub a8: Vec<u32>,
}

#[derive(Deserialize, Debug)]
pub struct DD {
  pub a1: Vec<Vec<u32>>,
  pub a2: Vec<Vec<u32>>,
  pub a3: Vec<Vec<u32>>,
  pub a4: Vec<Vec<u32>>,
  pub a5: Vec<Vec<u32>>,
  pub a6: Vec<Vec<u32>>,
  pub a7: Vec<Vec<u32>>,
  pub a8: Vec<Vec<u32>>,
}

#[derive(Deserialize, Debug)]
pub struct DE {
  pub a: AL,
  pub b: Vec<u64>,
  pub e: NAL,
}

#[derive(Deserialize, Debug)]
pub struct AL {
  pub a: Vec<u32>,
  pub b: HashMap<String, VDE>,
}

#[derive(Deserialize, Debug)]
pub struct VDE {
  pub a: u64,
  pub b: Vec<u32>,
}

#[derive(Deserialize, Debug)]
pub struct NAL {
  pub a: Vec<u32>,
  pub b: Vec<CGDE>,
}

#[derive(Deserialize, Debug)]
pub struct CGDE {
  pub a: u64,
  pub b: Vec<u32>,
  pub c: usize,
  pub d: HashMap<String, VDE>,
  pub e: Vec<CGDE>,
}


#[derive(Deserialize, Debug)]
#[serde(tag = "type")]
pub enum CG {
  Se(Se),
  Sh(Sh),
  Sw(Sw),
  Re(Re),
  ReWh(ReWh),
  If(If),
  IfElse(IfElse),
  Call(Call),
  OTE(OTE),
  DX(DX),
  GX(GX),
  SCo(SCo),
  CSS(CSS),
  Sync(Sync),
  SLC(SLC),
  SLCFV(SLCFV),
  GLC(GLC),
  ATF(ATF),
  ATVE(ATVE),
  WU(WU),
  SSSS(SSSS),
  Sans(Sans),
  Sans2(Sans2),
  Tif(Tif),
}

#[derive(Deserialize, Debug)]
pub struct Se {
  pub c: Vec<usize>,
}

#[derive(Deserialize, Debug)]
pub struct Sh {
  pub c: Vec<usize>, // 1 child
}

#[derive(Deserialize, Debug)]
pub struct Sw {
  pub c: Vec<usize>,
}

#[derive(Deserialize, Debug)]
pub struct Re {
  pub c: Vec<usize>, // 1 child
}

#[derive(Deserialize, Debug)]
pub struct ReWh {
  pub c: Vec<usize>, // 1st child is condition, 2nd is body.
}

#[derive(Deserialize, Debug)]
pub struct If {
  pub c: Vec<usize>, // 1st child is true body, 2nd is false body.
}

#[derive(Deserialize, Debug)]
pub struct IfElse {
  pub c: Vec<usize>,
}

#[derive(Deserialize, Debug)]
pub struct Call {
  pub a: usize,
}

#[derive(Deserialize, Debug)]
pub struct OTE {
  pub b: usize,
}

#[derive(Deserialize, Debug)]
pub struct DX {
  pub a: usize,
  pub b: String,
}

#[derive(Deserialize, Debug)]
pub struct GX {
  pub a: usize,
  pub b: String,
}

#[derive(Deserialize, Debug)]
pub struct SCo {
  pub a: usize,
}

#[derive(Deserialize, Debug)]
pub struct CSS {
  pub a: usize,
}

#[derive(Deserialize, Debug)]
pub struct Sync {
  pub a: SyTy,
}

#[derive(Deserialize, Debug)]
pub struct SLC {
}

#[derive(Deserialize, Debug)]
pub struct SLCFV {
}

#[derive(Deserialize, Debug)]
pub struct GLC {
}

#[derive(Deserialize, Debug)]
pub struct ATF {
}

#[derive(Deserialize, Debug)]
pub struct ATVE {
}

#[derive(Deserialize, Debug)]
pub struct WU {
}

#[derive(Deserialize, Debug)]
pub struct SSSS {
}

#[derive(Deserialize, Debug)]
pub struct Sans {
  pub a: Vec<u32>,
}

#[derive(Deserialize, Debug)]
pub struct Sans2 {
  pub a: Vec<u32>,
}

#[derive(Deserialize, Debug)]
pub struct Tif {
  pub c: Vec<usize>,
}

#[derive(Deserialize, Debug)]
pub enum SyTy {
  Internal,
  External,
}

pub fn read_file(
  filename: &Path,
) -> Result<CA> {

  let file = File::open(filename)?;

  let reader = BufReader::new(file);

  Ok(serde_cbor::from_reader(reader)?)
}

fn main() -> Result<()> {
    let gp = read_file(Path::new("foo"))?;
    dbg!(gp);
    Ok(())
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions