Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(parser,diagnostic): one diagnostic struct to eliminate monomorphization of generic types #3214

Merged
merged 1 commit into from May 11, 2024

Conversation

Boshen
Copy link
Member

@Boshen Boshen commented May 9, 2024

part of #3213

We should only have one diagnostic struct instead 353 copies of them, so we don't end up choking LLVM with 50k lines of the same code due to monomorphization.

If the proposed approach is good, then I'll start writing a codemod to turn all the existing structs to plain functions.


Background:

Using --timings, we see oxc_linter is slow on codegen (the purple part).

image

The crate currently contains 353 miette errors. cargo-llvm-lines displays

cargo llvm-lines -p oxc_linter --lib --release

  Lines                 Copies               Function name
  -----                 ------               -------------
  830350                33438                (TOTAL)
   29252 (3.5%,  3.5%)    808 (2.4%,  2.4%)  <alloc::boxed::Box<T,A> as core::ops::drop::Drop>::drop
   23298 (2.8%,  6.3%)    353 (1.1%,  3.5%)  miette::eyreish::error::object_downcast
   19062 (2.3%,  8.6%)    706 (2.1%,  5.6%)  core::error::Error::type_id
   12610 (1.5%, 10.1%)     65 (0.2%,  5.8%)  alloc::raw_vec::RawVec<T,A>::grow_amortized
   12002 (1.4%, 11.6%)    706 (2.1%,  7.9%)  miette::eyreish::ptr::Own<T>::boxed
    9215 (1.1%, 12.7%)    115 (0.3%,  8.2%)  core::iter::traits::iterator::Iterator::try_fold
    9150 (1.1%, 13.8%)      1 (0.0%,  8.2%)  oxc_linter::rules::RuleEnum::read_json
    8825 (1.1%, 14.9%)    353 (1.1%,  9.3%)  <miette::eyreish::error::ErrorImpl<E> as core::error::Error>::source
    8822 (1.1%, 15.9%)    353 (1.1%, 10.3%)  miette::eyreish::error::<impl miette::eyreish::Report>::construct
    8119 (1.0%, 16.9%)    353 (1.1%, 11.4%)  miette::eyreish::error::object_ref
    8119 (1.0%, 17.9%)    353 (1.1%, 12.5%)  miette::eyreish::error::object_ref_stderr
    7413 (0.9%, 18.8%)    353 (1.1%, 13.5%)  <miette::eyreish::error::ErrorImpl<E> as core::fmt::Display>::fmt
    7413 (0.9%, 19.7%)    353 (1.1%, 14.6%)  miette::eyreish::ptr::Own<T>::new
    6669 (0.8%, 20.5%)     39 (0.1%, 14.7%)  alloc::raw_vec::RawVec<T,A>::try_allocate_in
    6173 (0.7%, 21.2%)    353 (1.1%, 15.7%)  miette::eyreish::error::<impl miette::eyreish::Report>::from_std
    6027 (0.7%, 21.9%)     70 (0.2%, 16.0%)  <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
    6001 (0.7%, 22.7%)    353 (1.1%, 17.0%)  miette::eyreish::error::object_drop
    6001 (0.7%, 23.4%)    353 (1.1%, 18.1%)  miette::eyreish::error::object_drop_front
    5648 (0.7%, 24.1%)    353 (1.1%, 19.1%)  <miette::eyreish::error::ErrorImpl<E> as core::fmt::Debug>::fmt

It's totalling more than 50k llvm lines, and is putting pressure on rustc codegen (the purple part on oxc_linter in the image above.


It's pretty obvious by looking at https://github.com/zkat/miette/blob/main/src/eyreish/error.rs, the generics can expand out to lots of code.

@Boshen Boshen requested a review from Dunqing May 9, 2024 08:07
@github-actions github-actions bot added the A-parser Area - Parser label May 9, 2024
Copy link

codspeed-hq bot commented May 9, 2024

CodSpeed Performance Report

Merging #3214 will improve performances by 11.24%

Comparing redo-diagnostics (2064ae9) with main (46c02ae)

Summary

⚡ 4 improvements
✅ 23 untouched benchmarks

Benchmarks breakdown

Benchmark main redo-diagnostics Change
lexer[RadixUIAdoptionSection.jsx] 100.2 µs 90.1 µs +11.24%
lexer[antd.js] 117 ms 113.6 ms +3.05%
parser[RadixUIAdoptionSection.jsx] 282.1 µs 270.3 µs +4.37%
parser[cal.com.tsx] 124.3 ms 120.3 ms +3.31%

@Boshen Boshen changed the title refactor(diagnostic): 1 diagnostic refactor(diagnostic): one diagnostic struct May 9, 2024
@Boshen Boshen changed the title refactor(diagnostic): one diagnostic struct refactor(diagnostic): one diagnostic struct to eliminate generic monomorphization May 9, 2024
@Boshen Boshen changed the title refactor(diagnostic): one diagnostic struct to eliminate generic monomorphization refactor(diagnostic): one diagnostic struct to eliminate monomorphization of generic types May 9, 2024
crates/oxc_diagnostics/src/lib.rs Outdated Show resolved Hide resolved
@elenakrittik
Copy link

Would it be better to use miette's built-in MietteDiagnostic instead of a custom type? Or do you expect the cost of String allocations to be too high?

@Boshen
Copy link
Member Author

Boshen commented May 9, 2024

Would it be better to use miette's built-in MietteDiagnostic instead of a custom type? Or do you expect the cost of String allocations to be too high?

How did I miss this after all these time (2 years) ... and there is a macro too! https://docs.rs/miette/latest/miette/macro.diagnostic.html

@Boshen Boshen force-pushed the redo-diagnostics branch 3 times, most recently from a607fb4 to 5dd98a1 Compare May 10, 2024 04:12
@Boshen
Copy link
Member Author

Boshen commented May 10, 2024

Would it be better to use miette's built-in MietteDiagnostic instead of a custom type? Or do you expect the cost of String allocations to be too high?

Haha, rust complained, back to creating our own struct

error: the `Err`-variant returned from this function is very large
   --> crates/oxc_parser/src/lib.rs:338:36
    |
338 |     fn parse_program(&mut self) -> Result<Program<'a>> {
    |                                    ^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes

1 similar comment
@Boshen
Copy link
Member Author

Boshen commented May 10, 2024

Would it be better to use miette's built-in MietteDiagnostic instead of a custom type? Or do you expect the cost of String allocations to be too high?

Haha, rust complained, back to creating our own struct

error: the `Err`-variant returned from this function is very large
   --> crates/oxc_parser/src/lib.rs:338:36
    |
338 |     fn parse_program(&mut self) -> Result<Program<'a>> {
    |                                    ^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes

@github-actions github-actions bot added the A-linter Area - Linter label May 10, 2024
@Boshen Boshen force-pushed the redo-diagnostics branch 2 times, most recently from 0cf90e8 to 784da2d Compare May 10, 2024 17:05
@Boshen Boshen marked this pull request as ready for review May 10, 2024 17:16
@Boshen Boshen changed the title refactor(diagnostic): one diagnostic struct to eliminate monomorphization of generic types refactor(parser,diagnostic): one diagnostic struct to eliminate monomorphization of generic types May 10, 2024
@Boshen Boshen marked this pull request as draft May 10, 2024 17:21
@Boshen
Copy link
Member Author

Boshen commented May 10, 2024

Binary size for cargo build --release --example parser shrank from 1.0M to 958K. Big win!

@Boshen Boshen marked this pull request as ready for review May 10, 2024 17:28
@Boshen Boshen requested a review from overlookmotel May 10, 2024 17:28
@Dunqing
Copy link
Member

Dunqing commented May 11, 2024

Very much looking forward to shrinking in the linter!

@Boshen Boshen added this pull request to the merge queue May 11, 2024
@Boshen Boshen removed this pull request from the merge queue due to the queue being cleared May 11, 2024
@Boshen Boshen added the merge label May 11, 2024
Copy link

graphite-app bot commented May 11, 2024

Merge activity

  • May 11, 12:55 AM EDT: The merge label 'merge' was detected. This PR will be added to the Graphite merge queue once it meets the requirements.
  • May 11, 12:55 AM EDT: Boshen added this pull request to the Graphite merge queue.
  • May 11, 1:00 AM EDT: Boshen merged this pull request with the Graphite merge queue.

…orphization of generic types (#3214)

part of #3213

We should only have one diagnostic struct instead 353 copies of them, so we don't end up choking LLVM with 50k lines of the same code due to monomorphization.

If the proposed approach is good, then I'll start writing a codemod to turn all the existing structs to plain functions.

---

Background:

Using `--timings`, we see `oxc_linter` is slow on codegen (the purple part).

![image](https://github.com/zkat/miette/assets/1430279/c1df4f7d-90ef-4c0f-9956-2ec3194db7ca)

The crate currently contains 353 miette errors. [cargo-llvm-lines](https://github.com/dtolnay/cargo-llvm-lines) displays

```
cargo llvm-lines -p oxc_linter --lib --release

  Lines                 Copies               Function name
  -----                 ------               -------------
  830350                33438                (TOTAL)
   29252 (3.5%,  3.5%)    808 (2.4%,  2.4%)  <alloc::boxed::Box<T,A> as core::ops::drop::Drop>::drop
   23298 (2.8%,  6.3%)    353 (1.1%,  3.5%)  miette::eyreish::error::object_downcast
   19062 (2.3%,  8.6%)    706 (2.1%,  5.6%)  core::error::Error::type_id
   12610 (1.5%, 10.1%)     65 (0.2%,  5.8%)  alloc::raw_vec::RawVec<T,A>::grow_amortized
   12002 (1.4%, 11.6%)    706 (2.1%,  7.9%)  miette::eyreish::ptr::Own<T>::boxed
    9215 (1.1%, 12.7%)    115 (0.3%,  8.2%)  core::iter::traits::iterator::Iterator::try_fold
    9150 (1.1%, 13.8%)      1 (0.0%,  8.2%)  oxc_linter::rules::RuleEnum::read_json
    8825 (1.1%, 14.9%)    353 (1.1%,  9.3%)  <miette::eyreish::error::ErrorImpl<E> as core::error::Error>::source
    8822 (1.1%, 15.9%)    353 (1.1%, 10.3%)  miette::eyreish::error::<impl miette::eyreish::Report>::construct
    8119 (1.0%, 16.9%)    353 (1.1%, 11.4%)  miette::eyreish::error::object_ref
    8119 (1.0%, 17.9%)    353 (1.1%, 12.5%)  miette::eyreish::error::object_ref_stderr
    7413 (0.9%, 18.8%)    353 (1.1%, 13.5%)  <miette::eyreish::error::ErrorImpl<E> as core::fmt::Display>::fmt
    7413 (0.9%, 19.7%)    353 (1.1%, 14.6%)  miette::eyreish::ptr::Own<T>::new
    6669 (0.8%, 20.5%)     39 (0.1%, 14.7%)  alloc::raw_vec::RawVec<T,A>::try_allocate_in
    6173 (0.7%, 21.2%)    353 (1.1%, 15.7%)  miette::eyreish::error::<impl miette::eyreish::Report>::from_std
    6027 (0.7%, 21.9%)     70 (0.2%, 16.0%)  <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
    6001 (0.7%, 22.7%)    353 (1.1%, 17.0%)  miette::eyreish::error::object_drop
    6001 (0.7%, 23.4%)    353 (1.1%, 18.1%)  miette::eyreish::error::object_drop_front
    5648 (0.7%, 24.1%)    353 (1.1%, 19.1%)  <miette::eyreish::error::ErrorImpl<E> as core::fmt::Debug>::fmt
```

It's totalling more than 50k llvm lines, and is putting pressure on rustc codegen (the purple part on `oxc_linter` in the image above.

---

It's pretty obvious by looking at https://github.com/zkat/miette/blob/main/src/eyreish/error.rs, the generics can expand out to lots of code.
@graphite-app graphite-app bot merged commit 2064ae9 into main May 11, 2024
29 checks passed
@graphite-app graphite-app bot deleted the redo-diagnostics branch May 11, 2024 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linter Area - Linter A-parser Area - Parser merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants