-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Detailed panic messages for Vec functions #70573
Detailed panic messages for Vec functions #70573
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @LukasKalbertodt (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
src/liballoc/vec.rs
Outdated
@@ -992,7 +992,7 @@ impl<T> Vec<T> { | |||
#[stable(feature = "rust1", since = "1.0.0")] | |||
pub fn insert(&mut self, index: usize, element: T) { | |||
let len = self.len(); | |||
assert!(index <= len); | |||
assert!(index <= len, "index out of bounds: the len is {} but the index is {}", len, index); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that the bounds check for insert
functions is different from indexing (<=
rather than <
), I wonder if it makes sense to also make the error different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if we want to be really sure this behaves like indexing, we could make core::panicking::panic_bounds_check
public and call it (though until the next bootstrap bump, that requires conditional compilation unfortunately).
I am not sure if that's worth it, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that the bounds check for insert functions is different from indexing (<= rather than <), I wonder if it makes sense to also make the error different?
I was thinking on how to check all three boxes:
- don't fall into bloated error message
- introduce argument values
- keep it consistent with everything else (basically
[]
call)
Other than that, I think bringing both conditions and parameters might work better. However, if we want to add some human-readable explanation, it gets really big, like that
assert!("index out of bounds, index should be <= len, got {} <= {}", index, len);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, now I'm thinking that is has an appropriate size, but then it will require core::panicking::panic_bounds_check
to be updated, to bring condition there too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No the condition would have to stay here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate? I think I didn't get the context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just saying that function must not change.
But in the end it probably is better to just do what you did, and not try to literally share the message with indexing... I was just bringing up the possibility.
@RalfJung I've decided to follow approach of having detailed message so it's easy to understand:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your PR! I have two main comments:
I don't quite like the second part of your error messages. The first part (stating the condition) is nice. But the second part is not explicit enough for me. For example, instead of
insertion index should be <= len, got {} <= {}", index, len
... I would write something like this:
insertion index should be <= len, but the insertion index is {} and len is {}", index, len
This, of course, is not a particularly nice English as we will repeat the names (indices/len) a lot. I think clarity and explicitness in these error messages is more important than nice English, but maybe we can improve it still. How about one of these?
"assertion `index <= len` failed: insertion index is {} and len is {}"
"index out of bounds: insertion index is {} and len is {}, but `index <= len` should hold"
My second concern is performance. These are methods potentially called in hot loops. Panicking with a static string generates way less code than using the fmt machinery. And making those methods larger influences icache and inlining behavior, having a potentially large impact on performance. This could be (at least partially) mitigated by created special #[cold]
functions that simply panic. In any case, I'd like to check with @rust-timer
.
Ok, let's try talking to a new bot ^_^ @bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit e67919adffdb23fc074b0239a4e2ceee15dd1a1f with merge 2b82da36cfffe01ebec5f1e184def6270b747859... |
☀️ Try build successful - checks-azure |
Queued 2b82da36cfffe01ebec5f1e184def6270b747859 with parent 75ff311, future comparison URL. |
I prefer first one among options you mentioned - it's more concise and as informative as second.
I've been thinking about another approach as well: I saw this idiom somewhere outside Rust ecosystem and I like it, what are your thoughts about it? |
Slightly modified?
I think the "is" make it slightly clearer. What do you think? I'd be fine with that. EDIT: Although... this one isn't clearly stating a problem. The form "X should Y, but" conveys a problem, as does "assertion X failed". The form "X should Y" only states the condition and the user has to "deduce" that that condition was violated. Mhhhh |
I like it either, it's that I used to the template w/o 'is', but I agree that would be better in general.
Isn't the fact that panic occurred states it? Maybe a bit implicit, but still |
Just to be clear, this is just nitpicking on my side. I'm fine with the version I posted in my last comment (with "is"). Just take any of the ones I labeled as "fine" ^_^ |
Ok, got it ^^ |
I just noticed it already shows results. I would have expected another comment of the bot here, telling us the comparison is done. Anyway... The results don't look too good I think. Basically every test case slowed down by between 0.1% and 0.8%. While this sounds minor, if this change is really caused by this change, I'm not particularly comfortable merging this as is. To put the numbers in perspective: PRs that improve compile times by half a percent across all test cases are rare and a really great achievement. Now I'm not sure if this change could also be caused by something else. I will ask someone :) |
A possible experiment would be go back to my weird idea from earlier, and call So the checks would become something like if index >= len { panic_bounds_check(index, len) } Except this will only work on if index >= len {
#[cfg(not(bootstrap))]
panic_bounds_check(index, len);
#[cfg(bootstrap)]
panic_bounds_check(Location::caller(), index, len);
} |
I just talked to @IgorPerikov Could you rewrite this so that the formatting is done in a separate #[cold]
#[inline(never)] // <-- probably implied by `#[cold]` but no one knows for sure...
fn assert_failed(index: usize, len: usize) -> ! {
panic!("insertion index (is {}) should be <= len (is {})", index, len);
}
if index > len {
assert_failed(index, len);
} (The With that changed for all methods, we can run the perf test again to see if that improved things. |
@LukasKalbertodt potentially |
@RalfJung Good idea! As we posted the previous comments at the same time: your suggestion with |
Exactly. Specifically, this is the cold function that is used to raise the panic on out-of-bounds slice/array/vector access. So it makes sense to call that whenever the error message should be exactly the same as for indexing. |
I definitely lack a lot of fundamental knowledge about how Rust works under the hood. One of the things I don't understand is this statement:
How is that possible if I also don't get it, how can we reuse
Maybe it's getting too hard for a novice like me 🤷♂ |
I think what @RalfJung was saying is: it is optimized to be inside hot loops without being actually called at runtime. Let me explain
Yes, it would just be useful for the cases with the exact behavior and error message we want, which is only
Nah, don't worry, you got this. Just ask if anything is unclear. For now, just do what I described in this comment. If anything about that is unclear, just ask. Also feel free to contact me via Zulip or Discord. |
Indeed I do, sorry for not being clearer. |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
it means improvement? |
No, runtime goes up by 2.4%. |
@nnethercote @eddyb @Zoxc Could someone of you maybe help us interpret these perf results? So I guess if we have any measurable regression, we probably don't want to merge this. We are just not sure if this is a regression. |
Regression with "clean" but not "baseline incremental" is likely noise, incremental should be strictly slower, and the regression in If I had to guess, this PR doesn't observably change the performance of |
The 2.6% |
@nnethercote That's the one I was saying I don't believe is real because I would expect "baseline incremental" to regress in the same way as "clean", and it doesn't. |
My PR changing |
Concerning performance: I guess we can land this PR then. If it turns out to have a notably speed decrease in practice, we can still revert or tweak it. Coincidentally, a while back, I wrote a few benchmarks that make heavy use of |
Agreed, but let's also do @bors rollup=never for easier bisecting. |
Sure, will do! |
Soo.. I've messed up something. Tbh got used to strategy of merging whatever I need and then squash-merging into master I guess it'd be easier to create new pr against master with needed changes and link to this for discussions history, @LukasKalbertodt are u agree? |
I'd be fine with that. Be sure to include |
@IgorPerikov Just run |
This didn't work out as I was forced to resolve all the conflicts, solving them and continuing didn't help, so I skipped and force-pushed. I suppose it should be fine now |
Ah, hmm, if you had duplicated history compared to Anyway I'm glad the PR is saved :). |
@IgorPerikov I know this isn't the best time to ask this (as you just had lots of git trouble), but could you squash your commits into one or two? Currently there are many commits that don't compile. This makes the git history somewhat meh. If you need help with squashing, be sure to ask, we can help. (I'm pretty busy right now, but I can provide more information later, if you want.) |
@LukasKalbertodt no-no It's okay for sure :) I can do it manually (this time I am familiar with procedure), but isn't squash and merge (in github merge pr dropdown menu) would solve it too? |
Yeah but we don't merge via that button. We have a bot that makes sure full CI (all 30+ runners, not just the few that you can see in this PR already) passes on the merged state before putting anything to master. That bot unfortunately has no auto-squashing ability. |
Looks good to me. Thanks a bunch for squashing and updating the PR :) @bors r+ rollup=never |
📌 Commit 9fc77c0 has been approved by |
Thanks everyone for all the valuable tips and infos. Your support was one in a kind actually |
☀️ Test successful - checks-azure |
Finally managed to do this. I compared nightly-2020-04-05 and nightly 2020-04-10. I couldn't see any differences in my benchmark apart from noise. So that's another hint that this change doesn't cause a notable performance regression. |
pass indexes to insert, remove, drain, and split_off panic messages
closes #70524