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

std: remove an allocation in Path::with_extension #113106

Merged

Conversation

marcospb19
Copy link
Contributor

Path::with_extension used to reallocate (and copy) paths twice per call, now it does it once, by checking the size of the previous and new extensions it's possible to call PathBuf::with_capacity and pass the exact capacity required.

This also reduces the memory consumption of the path returned from Path::with_extension by using exact capacity instead of using amortized exponential growth.

@rustbot
Copy link
Collaborator

rustbot commented Jun 27, 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 Jun 27, 2023
library/std/src/path.rs Outdated Show resolved Hide resolved
`Path::with_extension` used to reallocate (and copy) paths twice per
call, now it does it once, by checking the size of the previous and new
extensions it's possible to call `PathBuf::with_capacity` and pass the
exact capacity it takes.

Also reduce the memory consumption of the path returned from
`Path::with_extension` by using exact capacity instead of using
amortized exponential growth.
@marcospb19 marcospb19 force-pushed the improve-path-with-extension-function branch from 3346752 to 11f35d6 Compare June 27, 2023 21:46
@thomcc
Copy link
Member

thomcc commented Jun 28, 2023

@rustbot author

(Please do rustbot ready when you have added tests and it will go back into my queue, thanks)

@rustbot rustbot 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 Jun 28, 2023
Comment on lines +1412 to +1424
twe!("foo", "txt", "foo.txt");
twe!("foo.bar", "txt", "foo.txt");
twe!("foo.bar.baz", "txt", "foo.bar.txt");
twe!(".test", "txt", ".test.txt");
twe!("foo.txt", "", "foo");
twe!("foo", "", "foo");
twe!("", "foo", "");
twe!(".", "foo", ".");
twe!("foo/", "bar", "foo.bar");
twe!("foo/.", "bar", "foo.bar");
twe!("..", "foo", "..");
twe!("foo/..", "bar", "foo/..");
twe!("/", "foo", "/");
Copy link
Contributor Author

@marcospb19 marcospb19 Jul 14, 2023

Choose a reason for hiding this comment

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

After inspecting these, I realized that my implementation over-allocates in some of the corner cases.

/* ok     */ twe!("foo", "txt", "foo.txt");
/* ok     */ twe!("foo.bar", "txt", "foo.txt");
/* ok     */ twe!("foo.bar.baz", "txt", "foo.bar.txt");
/* ok     */ twe!(".test", "txt", ".test.txt");
/* over 1 */ twe!("foo.txt", "", "foo");
/* over 1 */ twe!("foo", "", "foo");
/* over 4 */ twe!("", "foo", "");
/* over 4 */ twe!(".", "foo", ".");
/* over 1 */ twe!("foo/", "bar", "foo.bar");
/* over 1 */ twe!("foo/.", "bar", "foo.bar");
/* over 4 */ twe!("..", "foo", "..");
/* over 4 */ twe!("foo/..", "bar", "foo/..");
/* over 4 */ twe!("/", "foo", "/");

For this one specifically, it does an extra (potentially) unused allocation, because it's an empty path:

/* over 4 */ twe!("", "foo", "");

EDIT: I believe they're mostly OK, because I assume that 99% of calls fit in the first 4 scenarios (or are only over-allocating 1 byte), but please let me know what you think.

Comment on lines +1426 to +1434
// New extension is smaller than file name
twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb");
// New extension is greater than file name
twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa");

// New extension is smaller than previous extension
twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.bbb_bbb");
// New extension is greater than previous extension
twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.aaa_aaa_aaa");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are necessary to get the bug you spotted.

The other tests do not, because they all use foo, bar and baz, which all contain the same length, this can be a problem in the case of some hidden bugs that only manifest when the path piece sizes are different.

@marcospb19
Copy link
Contributor Author

@rustbot ready
Added tests for Path::with_extension.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 14, 2023
@thomcc
Copy link
Member

thomcc commented Jul 20, 2023

Thanks!
@bors r+

@bors
Copy link
Contributor

bors commented Jul 20, 2023

📌 Commit 6ffca76 has been approved by thomcc

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 Jul 20, 2023
@bors
Copy link
Contributor

bors commented Jul 21, 2023

⌛ Testing commit 6ffca76 with merge 1a44b45...

@bors
Copy link
Contributor

bors commented Jul 21, 2023

☀️ Test successful - checks-actions
Approved by: thomcc
Pushing 1a44b45 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jul 21, 2023
@bors bors merged commit 1a44b45 into rust-lang:master Jul 21, 2023
11 checks passed
@rustbot rustbot added this to the 1.73.0 milestone Jul 21, 2023
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (1a44b45): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

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

Max RSS (memory usage)

Results

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.4% [0.4%, 0.4%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.4% [-3.4%, -3.4%] 1
All ❌✅ (primary) 0.4% [0.4%, 0.4%] 1

Cycles

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

Binary size

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

Bootstrap: 650.755s -> 650.086s (-0.10%)

@marcospb19 marcospb19 deleted the improve-path-with-extension-function branch July 24, 2023 15:21
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. 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.

5 participants