Skip to content

Minimal toml configuration could compile more quickly #1028

@hanna-kruppe

Description

@hanna-kruppe

Context: I'm currently using toml-span as dev-dependency for parsing files in a data-driven test harness, not entirely unlike trycmd's TOML files. The schema is very simple and all files are authored by developers, so the bugs in toml-spec aren't a serious concern for that use case.

I've previously picked toml-span over toml 0.8 for this because of compile times and because it didn't pull in serde. Now that toml 0.9 supports a configuration ("parse" feature only) that's closer to toml-span in terms of scope, compile time, and dependency tree, I'm looking into switching to the more popular, correct, and maintained library.

Unfortunately toml-span 0.5.2 still compiles faster than toml 0.9.5. This is not necessarily a blocker, but I'd like to highlight it in case it can be fixed without too much trouble. As a self-contained example, for a hello world binary that depends on nothing else but toml (parse only) or toml-span respectively, the former takes ca. 2x longer to compile in dev profile:

$ cargo new test-build-toml && cd test-build-toml/
$ cargo add [email protected] --no-default-features -F parse
$ hyperfine -w2 'cargo build -j1' --prepare 'cargo clean'
Benchmark 1: cargo build -j1
  Time (mean ± σ):      2.440 s ±  0.048 s    [User: 2.037 s, System: 0.277 s]
  Range (min … max):    2.380 s …  2.539 s    10 runs

$ hyperfine -w2 'cargo build' --prepare 'cargo clean'
Benchmark 1: cargo build
  Time (mean ± σ):      1.784 s ±  0.028 s    [User: 2.279 s, System: 0.281 s]
  Range (min … max):    1.756 s …  1.849 s    10 runs

$ cargo remove toml && cargo add [email protected]
$ hyperfine -w2 'cargo build ' --prepare 'cargo clean'
Benchmark 1: cargo build
  Time (mean ± σ):     810.5 ms ±  19.8 ms    [User: 1039.5 ms, System: 176.7 ms]
  Range (min … max):   787.2 ms … 840.8 ms    10 runs

$ hyperfine -w2 'cargo build -j1 ' --prepare 'cargo clean'
Benchmark 1: cargo build -j1
  Time (mean ± σ):      1.148 s ±  0.016 s    [User: 0.888 s, System: 0.147 s]
  Range (min … max):    1.123 s …  1.172 s    10 runs

This appears to be entirely due to using winnow: it accounts for 1.3sec of the build time on my machine. I wouldn't question this if the toml crates were still written with parser combinators. But from a quick survey, it seems that only a few bits and pieces from winnow::stream are used, amounting to a tiny fraction of winnow. I've not looked into every single usage but most of them seem either trivial to avoid entirely (e.g., AsBStr in this context only provides a different name for str::as_bytes) or not too hard to extract into something free-standing (e.g., substring search with optional use of memchr).

How would you feel about a PR that removes and/or extracts those bits and pieces so the toml crates don't need to depend on winnow at all?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions