-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Get piece unchecked in write
#83302
Get piece unchecked in write
#83302
Conversation
r? @sfackler (rust-highfive has picked a reviewer for you, use r? to override) |
This seems a little surprising. Iterators like |
This does not remove a bounds check within the loop. Only a length check of |
|
I added assertions. I think that shouldn't be an issue, unless someone is using |
1e04a07
to
dfb16ef
Compare
☔ The latest upstream changes (presumably #83580) made this pull request unmergeable. Please resolve the merge conflicts. |
dfb16ef
to
a24ced6
Compare
5eab7b6
to
e8ec0bb
Compare
This comment has been minimized.
This comment has been minimized.
e8ec0bb
to
18d508c
Compare
This comment has been minimized.
This comment has been minimized.
Now any unsafe block like // format_args!("hello {}", world)
match match (&world,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
} {
ref args => unsafe { ::core::fmt::Arguments::new_v1(&["hello "], args) },
}; Thoughts? |
@camsteffen Ping from triage, CI is still red here. Maybe you can use any change necessary to get CI green, so we can pass this on to the reviewer? |
18d508c
to
6a1fa08
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@rustbot label: +S-waiting-on-review -S-waiting-on-author |
This caused a large regression in instruction counts when testing the compiler. This is a largely a change in std lib code, and we don't really have a good process for dealing with how std lib changes effect performance. This seems to be primarily affecting debug and check builds, but there doesn't seem to be a query that is clearly to blame here. Given the motivation of this PR is primarily performance, I think it deserves a closer look. As part of the performance triage process, I'm marking this as a performance regression. If you believe this performance regression to be justifiable or once you have an issue or PR that addresses this regression, please mark this PR with the label perf-regression-triaged. @rustbot label +perf-regression |
…tolnay Get piece unchecked in `write` We already use specialized `zip`, but it seems like we can do a little better by not checking `pieces` length at all. `Arguments` constructors are now unsafe. So the `format_args!` expansion now includes an `unsafe` block. <details> <summary>Local Bench Diff</summary> ```text name before ns/iter after ns/iter diff ns/iter diff % speedup fmt::write_str_macro1 22,967 19,718 -3,249 -14.15% x 1.16 fmt::write_str_macro2 35,527 32,654 -2,873 -8.09% x 1.09 fmt::write_str_macro_debug 571,953 575,973 4,020 0.70% x 0.99 fmt::write_str_ref 9,579 9,459 -120 -1.25% x 1.01 fmt::write_str_value 9,573 9,572 -1 -0.01% x 1.00 fmt::write_u128_max 176 173 -3 -1.70% x 1.02 fmt::write_u128_min 138 134 -4 -2.90% x 1.03 fmt::write_u64_max 139 136 -3 -2.16% x 1.02 fmt::write_u64_min 129 135 6 4.65% x 0.96 fmt::write_vec_macro1 24,401 22,273 -2,128 -8.72% x 1.10 fmt::write_vec_macro2 37,096 35,602 -1,494 -4.03% x 1.04 fmt::write_vec_macro_debug 588,291 589,575 1,284 0.22% x 1.00 fmt::write_vec_ref 9,568 9,732 164 1.71% x 0.98 fmt::write_vec_value 9,516 9,625 109 1.15% x 0.99 ``` </details>
The regression seems to be caused by the change in the format_args! expansion which is now more complex in order to have an unsafe block that surrounds |
Hm. So #88571 does look to fix the majority of the regression here, but I suppose we cannot land it as-is due to the unsafe nesting causing some problems with spurious lints. I would lean towards reverting this PR; the small wins in runtime performance do not seem worth it given that fmt isn't optimized for performance anyway (indirect calls, can't get inlined, etc.). The compile time regressions are not insignificant. |
My only reservation with reverting is that the internal fmt API was already unsafe before this PR added the unsafe modifiers. |
I.. sort of doubt that the get_unchecked there matters that much either, so I'd at least be fine with dropping it too (in favor of safety) as part of a pseudo-revert. |
Looks like the justification is noted in the commit (so nice!) -- d80f127. I think that makes sense, but we could likely get away with something "not wrong" as a result without invoking the full panic machinery. e.g., We could also move the unsafety as an assertion into a ZST that the caller must construct via an unsafe method, which would get compiled out but also allow us to put the unsafe block in a more local place, rather than wrapping the whole function call. |
Use ZST for fmt unsafety as suggested here - rust-lang#83302 (comment).
Use ZST for fmt unsafety as suggested here - rust-lang/rust#83302 (comment).
@Mark-Simulacrum I'm thinking the next step here for perf triage is to do a perf run reverting this and the follow-up PRs? |
I think #89139 definitely helped with some of the regressions caused by this PR. I think a trial revert would still be good, though, to estimate how much of a performance hit this is with the mitigations in place (like ZST-based unsafe). |
The revert perf run looks good! #89521 (comment) |
Hm, the revert results feel a little unexpected. Unless there's been unrelated performance optimization that mitigates much of the regression seen in this PR, we would expect the revert to look equivalent, right? But instead we see barely any improvement. |
We already use specialized
zip
, but it seems like we can do a little better by not checkingpieces
length at all.Arguments
constructors are now unsafe. So theformat_args!
expansion now includes anunsafe
block.Local Bench Diff