about summary refs log tree commit diff
path: root/library/alloc/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-30 00:55:52 +0000
committerbors <bors@rust-lang.org>2024-07-30 00:55:52 +0000
commitdba8e2d2c2890a8b9e88cbf4855ac5711337946c (patch)
treef9953b1f9116fa393c44a4b3578ecc70f9451f66 /library/alloc/src
parent368e2fd458a22d0cc133d0c254f2612ee999744f (diff)
parent6a6824a0ab5c14b5343fe108f10ec40c146b97e4 (diff)
downloadrust-dba8e2d2c2890a8b9e88cbf4855ac5711337946c.tar.gz
rust-dba8e2d2c2890a8b9e88cbf4855ac5711337946c.zip
Auto merge of #128234 - jcsp:retain-empty-case, r=tgross35
Optimize empty case in Vec::retain

While profiling some code that happens to call Vec::retain() in a tight loop, I noticed more runtime than expected in retain, even in a bench case where the vector was always empty.  When I wrapped my call to retain in `if !myvec.is_empty()` I saw faster execution compared with doing retain on an empty vector.

On closer inspection, Vec::retain is doing set_len(0) on itself even when the vector is empty, and then resetting the length again in BackshiftOnDrop::drop.

Unscientific screengrab of a flamegraph illustrating how we end up spending time in set_len and drop:
![image](https://github.com/user-attachments/assets/ebc72ace-84a0-4432-9b6f-1b3c96d353ba)
Diffstat (limited to 'library/alloc/src')
-rw-r--r--library/alloc/src/vec/mod.rs6
1 files changed, 6 insertions, 0 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 5306c507487..dfd22204c81 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1710,6 +1710,12 @@ impl<T, A: Allocator> Vec<T, A> {
         F: FnMut(&mut T) -> bool,
     {
         let original_len = self.len();
+
+        if original_len == 0 {
+            // Empty case: explicit return allows better optimization, vs letting compiler infer it
+            return;
+        }
+
         // Avoid double drop if the drop guard is not executed,
         // since we may make some holes during the process.
         unsafe { self.set_len(0) };