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

Implementation of fmt::FormattingOptions #118159

Merged
merged 17 commits into from
Dec 7, 2024

Conversation

EliasHolzmann
Copy link
Contributor

@EliasHolzmann EliasHolzmann commented Nov 22, 2023

Tracking issue: #118117

Public API:

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FormattingOptions {}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Sign {
    Plus, 
    Minus
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugAsHex {
    Lower,
    Upper
}

impl FormattingOptions {
    pub fn new() -> Self;
    pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self;
    pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self;
    pub fn alternate(&mut self, alternate: bool) -> &mut Self;
    pub fn fill(&mut self, fill: char) -> &mut Self;
    pub fn align(&mut self, alignment: Option<Alignment>) -> &mut Self;
    pub fn width(&mut self, width: Option<usize>) -> &mut Self;
    pub fn precision(&mut self, precision: Option<usize>) -> &mut Self;
    pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self;

    pub fn get_sign(&self) -> Option<Sign>;
    pub fn get_sign_aware_zero_pad(&self) -> bool;
    pub fn get_alternate(&self) -> bool;
    pub fn get_fill(&self) -> char;
    pub fn get_align(&self) -> Option<Alignment>;
    pub fn get_width(&self) -> Option<usize>;
    pub fn get_precision(&self) -> Option<usize>;
    pub fn get_debug_as_hex(&self) -> Option<DebugAsHex>;

    pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a>;
    }

impl<'a> Formatter<'a> {
    pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self;
    pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b>;
    pub fn sign(&self) -> Option<Sign>;

    pub fn options(&self) -> FormattingOptions;
}

Relevant changes from the public API in the tracking issue (I'm leaving out some stuff I consider obvious mistakes, like missing #[derive(..)]s and pub specifiers):

  • enum DebugAsHex/FormattingOptions::debug_as_hex/FormattingOptions::get_debug_as_hex: To support {:x?} as well as {:X?}. I had completely missed these options in the ACP. I'm open for any and all bikeshedding, not married to the name.
  • fill/get_fill now takes/returns char instead of Option<char>. This simply mirrors what Formatter::fill returns (with default being ' ').
  • Changed zero_pad/get_zero_pad to sign_aware_zero_pad/get_sign_aware_zero_pad. This also mirrors Formatter::sign_aware_zero_pad. While I'm not a fan of this quite verbose name, I do believe that having the interface of Formatter and FormattingOptions be compatible is more important.
  • For the same reason, renamed alignment/get_alignment to aling/get_align.
  • Deviating from my initial idea, Formatter::with_options returns a Formatter which has the lifetime of the self reference as its generic lifetime parameter (in the original API spec, the generic lifetime of the returned Formatter was the generic lifetime used by self instead). Otherwise, one could construct two Formatters that both mutably borrow the same underlying buffer, which would be unsound. This solution still has performance benefits over simply using Formatter::new, so I believe it is worthwhile to keep this method.

@rustbot
Copy link
Collaborator

rustbot commented Nov 22, 2023

r? @thomcc

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Nov 22, 2023
@rust-log-analyzer

This comment has been minimized.

@EliasHolzmann
Copy link
Contributor Author

Looks like this broke some compiler tests. Will fix this evening, converting to draft PR for now.

@EliasHolzmann EliasHolzmann marked this pull request as draft November 22, 2023 10:36
@rust-log-analyzer

This comment has been minimized.

@EliasHolzmann
Copy link
Contributor Author

CI is green -> Converting back to "normal" (non-draft) PR.

@EliasHolzmann EliasHolzmann marked this pull request as ready for review November 22, 2023 23:27
@thomcc
Copy link
Member

thomcc commented Nov 24, 2023

I already have a pretty big review backlog and haven't been following this change (so I'd have to read the ACP to figure out how it's supposed to behave), so I'm going to reroll for now, sorry.

r? libs

@rustbot rustbot assigned m-ou-se and unassigned thomcc Nov 24, 2023
@rust-log-analyzer

This comment has been minimized.

@EliasHolzmann
Copy link
Contributor Author

Fixed two more issues I've stumbled onto while playing around with the PR changes (see commit descriptions for details). I'll fix the PR description to represent the current API.

@bors
Copy link
Contributor

bors commented Dec 30, 2023

☔ The latest upstream changes (presumably #116012) made this pull request unmergeable. Please resolve the merge conflicts.

@ThePuzzlemaker

This comment was marked as resolved.

@m-ou-se
Copy link
Member

m-ou-se commented Feb 15, 2024

enum DebugAsHex/FormattingOptions::debug_as_hex/FormattingOptions::get_debug_as_hex: To support {:x?} as well as {:X?}. I had completely missed these options in the ACP. I'm open for any and all bikeshedding, not married to the name.

We haven't decided yet what to do with the "debug as hex" flags. It's fine to have them as unstable, but we shouldn't stabilize an interface for those flags without a separate discussion. I've added it as an unresolved question to the tracking issue.

Comment on lines -247 to +521
flags: u32,
fill: char,
align: rt::Alignment,
width: Option<usize>,
precision: Option<usize>,
options: FormattingOptions,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a Formatter object bigger than before, because the flags field is now stored in the new FormattingOptions as separate fields.

We should check if that doesn't have any negative impact on performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a Formatter object bigger than before

Are you sure? Before, flags was a u32, so 4 bytes. With each flag in its own field, there are two bools and two small enums wrapped into Option – both should be one byte per field, so 4 bytes in total as well. Unless I'm not seeing something here, both the original code and the new implementation have the same size.

However, the benchmark shows a performance regression, and when I realized that Formatter didn't get bigger and therefore, flags may not be the culprit, I was already halfway through refactoring FormattingOptions to use a bitmask for flags (like it did before). So, either way, let's test that, it might help even if a difference in size is not the cause of the performance regression. Could you please rerun the benchmark?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure?

No :)

Before, flags was a u32, so 4 bytes. With each flag in its own field, there are two bools and two small enums wrapped into Option – both should be one byte per field, so 4 bytes in total as well.

Good point!

I think that in the near future we might want to put more things in the fields flag though. At least the alignment can easiliy fit in there, and the Some/None flag of the width and precision could fit in there as well:

pub struct FormattingOptions {
    flags: u32, // sign, zero pad, alt, debug-as-hex, width flag, precision flag, alignment
    fill: char,
    width: usize, // only used if width flag is set.
    precision: usize, // only used if width flag is set.
}

But maybe that's overkill.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub struct FormattingOptions {
    flags: u32, // sign, zero pad, alt, debug-as-hex, width flag, precision flag, alignment
    fill: char,
    width: usize, // only used if width flag is set.
    precision: usize, // only used if width flag is set.
}

well, fill has lots of spare bits, you could probably merge it with flags, where flags is just the upper bits and fill is the lower 21 bits. though this would only be beneficial on <= 32-bit systems unless width and precision were changed to be u32 or the struct was #[repr(packed(4))].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that there is definitely potential for further optimization here. I'll leave the solution using flags – while it is a bit harder to read, the possible performance benefits in the future seem more important to me.

The benchmark still reports a small performance regression (~0.1 %). While I don't think this is a big problem, it would still be nice if this PR would not introduce any performance regressions. To make the code more maintainable, I changed all internal accesses to formatting options to use the getters/setters on FormattingOptions instead of direct field access. I suspect this is at least a major factor in the performance regression. I have reverted this now, can you please rerun the benchmark @m-ou-se?

library/core/src/fmt/mod.rs Outdated Show resolved Hide resolved
library/core/src/fmt/mod.rs Outdated Show resolved Hide resolved
library/core/src/fmt/mod.rs Outdated Show resolved Hide resolved
library/core/src/fmt/mod.rs Outdated Show resolved Hide resolved
@m-ou-se
Copy link
Member

m-ou-se commented Feb 15, 2024

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@m-ou-se m-ou-se added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 15, 2024
@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Feb 15, 2024
@bors
Copy link
Contributor

bors commented Feb 15, 2024

⌛ Trying commit 385944a with merge 5085172...

bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 15, 2024
…<try>

Implementation of `fmt::FormatttingOptions`

Tracking issue: rust-lang#118117

Public API:
```rust
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FormattingOptions { … }
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Sign {
    Plus,
    Minus
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugAsHex {
    Lower,
    Upper
}

impl FormattingOptions {
    pub fn new() -> Self;
    pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self;
    pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self;
    pub fn alternate(&mut self, alternate: bool) -> &mut Self;
    pub fn fill(&mut self, fill: char) -> &mut Self;
    pub fn align(&mut self, alignment: Option<Alignment>) -> &mut Self;
    pub fn width(&mut self, width: Option<usize>) -> &mut Self;
    pub fn precision(&mut self, precision: Option<usize>) -> &mut Self;
    pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self;

    pub fn get_sign(&self) -> Option<Sign>;
    pub fn get_sign_aware_zero_pad(&self) -> bool;
    pub fn get_alternate(&self) -> bool;
    pub fn get_fill(&self) -> char;
    pub fn get_align(&self) -> Option<Alignment>;
    pub fn get_width(&self) -> Option<usize>;
    pub fn get_precision(&self) -> Option<usize>;
    pub fn get_debug_as_hex(&self) -> Option<DebugAsHex>;

    pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a>;
    }

impl<'a> Formatter<'a> {
    pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self;
    pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b>;
    pub fn sign(&self) -> Option<Sign>;

    pub fn options(&self) -> FormattingOptions;
}
```

Relevant changes from the public API in the tracking issue (I'm leaving out some stuff I consider obvious mistakes, like missing `#[derive(..)]`s and `pub` specifiers):

- `enum DebugAsHex`/`FormattingOptions::debug_as_hex`/`FormattingOptions::get_debug_as_hex`: To support `{:x?}` as well as `{:X?}`. I had completely missed these options in the ACP. I'm open for any and all bikeshedding, not married to the name.
- `fill`/`get_fill` now takes/returns `char` instead of `Option<char>`. This simply mirrors what `Formatter::fill` returns (with default being `' '`).
- Changed `zero_pad`/`get_zero_pad` to `sign_aware_zero_pad`/`get_sign_aware_zero_pad`. This also mirrors `Formatter::sign_aware_zero_pad`. While I'm not a fan of this quite verbose name, I do believe that having the interface of `Formatter` and `FormattingOptions` be compatible is more important.
- For the same reason, renamed `alignment`/`get_alignment` to `aling`/`get_align`.
- Deviating from my initial idea, `Formatter::with_options` returns a `Formatter` which has the lifetime of the `self` reference as its generic lifetime parameter (in the original API spec, the generic lifetime of the returned `Formatter` was the generic lifetime used by `self` instead). Otherwise, one could construct two `Formatter`s that both mutably borrow the same underlying buffer, which would be unsound. This solution still has performance benefits over simply using `Formatter::new`, so I believe it is worthwhile to keep this method.
@bors
Copy link
Contributor

bors commented Feb 15, 2024

☀️ Try build successful - checks-actions
Build commit: 5085172 (508517284df836989dd91522841c917d69eac778)

@m-ou-se
Copy link
Member

m-ou-se commented Dec 5, 2024

@bors try

bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 5, 2024
…<try>

Implementation of `fmt::FormattingOptions`

Tracking issue: rust-lang#118117

Public API:
```rust
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FormattingOptions { … }
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Sign {
    Plus,
    Minus
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugAsHex {
    Lower,
    Upper
}

impl FormattingOptions {
    pub fn new() -> Self;
    pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self;
    pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self;
    pub fn alternate(&mut self, alternate: bool) -> &mut Self;
    pub fn fill(&mut self, fill: char) -> &mut Self;
    pub fn align(&mut self, alignment: Option<Alignment>) -> &mut Self;
    pub fn width(&mut self, width: Option<usize>) -> &mut Self;
    pub fn precision(&mut self, precision: Option<usize>) -> &mut Self;
    pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self;

    pub fn get_sign(&self) -> Option<Sign>;
    pub fn get_sign_aware_zero_pad(&self) -> bool;
    pub fn get_alternate(&self) -> bool;
    pub fn get_fill(&self) -> char;
    pub fn get_align(&self) -> Option<Alignment>;
    pub fn get_width(&self) -> Option<usize>;
    pub fn get_precision(&self) -> Option<usize>;
    pub fn get_debug_as_hex(&self) -> Option<DebugAsHex>;

    pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a>;
    }

impl<'a> Formatter<'a> {
    pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self;
    pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b>;
    pub fn sign(&self) -> Option<Sign>;

    pub fn options(&self) -> FormattingOptions;
}
```

Relevant changes from the public API in the tracking issue (I'm leaving out some stuff I consider obvious mistakes, like missing `#[derive(..)]`s and `pub` specifiers):

- `enum DebugAsHex`/`FormattingOptions::debug_as_hex`/`FormattingOptions::get_debug_as_hex`: To support `{:x?}` as well as `{:X?}`. I had completely missed these options in the ACP. I'm open for any and all bikeshedding, not married to the name.
- `fill`/`get_fill` now takes/returns `char` instead of `Option<char>`. This simply mirrors what `Formatter::fill` returns (with default being `' '`).
- Changed `zero_pad`/`get_zero_pad` to `sign_aware_zero_pad`/`get_sign_aware_zero_pad`. This also mirrors `Formatter::sign_aware_zero_pad`. While I'm not a fan of this quite verbose name, I do believe that having the interface of `Formatter` and `FormattingOptions` be compatible is more important.
- For the same reason, renamed `alignment`/`get_alignment` to `aling`/`get_align`.
- Deviating from my initial idea, `Formatter::with_options` returns a `Formatter` which has the lifetime of the `self` reference as its generic lifetime parameter (in the original API spec, the generic lifetime of the returned `Formatter` was the generic lifetime used by `self` instead). Otherwise, one could construct two `Formatter`s that both mutably borrow the same underlying buffer, which would be unsound. This solution still has performance benefits over simply using `Formatter::new`, so I believe it is worthwhile to keep this method.
@bors
Copy link
Contributor

bors commented Dec 5, 2024

⌛ Trying commit 31a5657 with merge 9180b8f...

@bors
Copy link
Contributor

bors commented Dec 6, 2024

☀️ Try build successful - checks-actions
Build commit: 9180b8f (9180b8f2d8d524114162b5315df7de7b62b3f2fc)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (9180b8f): comparison URL.

Overall result: ❌✅ regressions and improvements - no action needed

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

This is the most reliable metric that we have; it was used to determine the overall result at the top of this comment. However, even this metric can sometimes exhibit noise.

mean range count
Regressions ❌
(primary)
0.5% [0.5%, 0.5%] 1
Regressions ❌
(secondary)
0.3% [0.3%, 0.3%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.4% [-0.4%, -0.4%] 1
All ❌✅ (primary) 0.5% [0.5%, 0.5%] 1

Max RSS (memory usage)

Results (primary -0.4%, secondary 1.8%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
2.9% [0.5%, 5.7%] 4
Regressions ❌
(secondary)
1.8% [0.7%, 3.0%] 2
Improvements ✅
(primary)
-4.8% [-10.3%, -0.6%] 3
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.4% [-10.3%, 5.7%] 7

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

Results (primary 0.0%, secondary 0.1%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
0.2% [0.0%, 0.4%] 60
Regressions ❌
(secondary)
0.3% [0.1%, 0.4%] 40
Improvements ✅
(primary)
-0.1% [-0.1%, -0.0%] 53
Improvements ✅
(secondary)
-0.2% [-0.7%, -0.0%] 49
All ❌✅ (primary) 0.0% [-0.1%, 0.4%] 113

Bootstrap: 770.008s -> 767.823s (-0.28%)
Artifact size: 330.85 MiB -> 330.89 MiB (0.01%)

@rustbot rustbot removed S-waiting-on-perf Status: Waiting on a perf run to be completed. perf-regression Performance regression. labels Dec 6, 2024
@m-ou-se
Copy link
Member

m-ou-se commented Dec 6, 2024

@bors r+

@bors
Copy link
Contributor

bors commented Dec 6, 2024

📌 Commit 31a5657 has been approved by m-ou-se

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 6, 2024
@bors
Copy link
Contributor

bors commented Dec 6, 2024

⌛ Testing commit 31a5657 with merge 75716b4...

@bors
Copy link
Contributor

bors commented Dec 7, 2024

☀️ Test successful - checks-actions
Approved by: m-ou-se
Pushing 75716b4 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Dec 7, 2024
@bors bors merged commit 75716b4 into rust-lang:master Dec 7, 2024
7 checks passed
@rustbot rustbot added this to the 1.85.0 milestone Dec 7, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (75716b4): comparison URL.

Overall result: ❌✅ regressions and improvements - please read the text below

Our benchmarks found a performance regression caused by this PR.
This might be an actual regression, but it can also be just noise.

Next Steps:

  • If the regression was expected or you think it can be justified,
    please write a comment with sufficient written justification, and add
    @rustbot label: +perf-regression-triaged to it, to mark the regression as triaged.
  • If you think that you know of a way to resolve the regression, try to create
    a new PR with a fix for the regression.
  • If you do not understand the regression or you think that it is just noise,
    you can ask the @rust-lang/wg-compiler-performance working group for help (members of this group
    were already notified of this PR).

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

Instruction count

This is the most reliable metric that we have; it was used to determine the overall result at the top of this comment. However, even this metric can sometimes exhibit noise.

mean range count
Regressions ❌
(primary)
0.3% [0.2%, 0.4%] 2
Regressions ❌
(secondary)
0.3% [0.3%, 0.3%] 1
Improvements ✅
(primary)
-0.4% [-0.4%, -0.4%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.1% [-0.4%, 0.4%] 3

Max RSS (memory usage)

Results (primary 0.3%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
2.8% [0.7%, 5.9%] 6
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-7.1% [-12.5%, -1.7%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.3% [-12.5%, 5.9%] 8

Cycles

Results (secondary 3.4%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
5.0% [2.0%, 7.5%] 7
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.3% [-2.4%, -2.2%] 2
All ❌✅ (primary) - - 0

Binary size

Results (primary 0.1%, secondary 0.1%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
0.2% [0.0%, 0.5%] 61
Regressions ❌
(secondary)
0.3% [0.1%, 0.5%] 51
Improvements ✅
(primary)
-0.1% [-0.1%, -0.0%] 53
Improvements ✅
(secondary)
-0.2% [-0.7%, -0.0%] 49
All ❌✅ (primary) 0.1% [-0.1%, 0.5%] 114

Bootstrap: 769.893s -> 768.721s (-0.15%)
Artifact size: 330.91 MiB -> 330.95 MiB (0.01%)

@rustbot rustbot added the perf-regression Performance regression. label Dec 7, 2024
@Mark-Simulacrum Mark-Simulacrum added the perf-regression-triaged The performance regression has been triaged. label Dec 9, 2024
@Mark-Simulacrum
Copy link
Member

Marking the perf regression as triaged. It doesn't seem to affect enough benchmarks to merit further investigation, especially given that this is an intentional change to the API surface (which seems likely to at least shift around e.g. CGUs and such and cause some amount of noise).

@EliasHolzmann
Copy link
Contributor Author

Thanks for getting this merged and triaged! Also, sorry for not reacting to the performance regression notification sooner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. perf-regression-triaged The performance regression has been triaged. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.