-
Notifications
You must be signed in to change notification settings - Fork 13k
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
"".to_string() is slower than String::new() #18404
Comments
It also allocates a lot of memory (128 bytes minimum) even for small / empty strings. |
This appears to be fixed. |
Only the capacity part of it. The code that creates the String instance is still awful. Apparently there's more inlining going on now, so the code for pub fn from_str() -> String {
String::from_str("")
} .section .text._ZN8from_str20h167891935c11e273laaE,"ax",@progbits
.globl _ZN8from_str20h167891935c11e273laaE
.align 16, 0x90
.type _ZN8from_str20h167891935c11e273laaE,@function
_ZN8from_str20h167891935c11e273laaE:
.cfi_startproc
movq $1, (%rdi)
movq $0, 16(%rdi)
movq $0, 8(%rdi)
movq %rdi, %rax
retq
.Ltmp44:
.size _ZN8from_str20h167891935c11e273laaE, .Ltmp44-_ZN8from_str20h167891935c11e273laaE
.cfi_endproc OTOH, this pub fn to_string() -> String {
"".to_string()
} gives you almost 200 lines of asm (including labels), and that still calls into |
extern crate test;
use test::{Bencher, black_box};
#[bench]
pub fn to_string(b: &mut Bencher) {
b.iter(|| {
black_box("".to_string());
});
}
#[bench]
pub fn from_str(b: &mut Bencher) {
b.iter(|| {
black_box(String::from_str(""));
});
}
|
A naive micro-benchmark won't be measuring the cost of reallocations. In the real world, it will rarely have room to expand in-place every time. |
Neither of those should allocate. You get a String without any allocated capacity in both cases. |
I'm aware. I'm pointing it out in advance so it can be done properly, because I'm sure measuring the cost of the repeated reallocations is going to be done too. |
What is the preferred way to do this these days? servo/servo#4682 is changing Servo to use |
Note that we can't just special case I have another idea though. How about we implement That won't solve the problem of allocating too much, but it might lessen the code bloat a bit. |
After some thought, I came up with another, simpler, idea. First, add a method to pub trait Display {
// ...
#[inline]
fn as_str_slice(&self) -> Option<&str> { None }
} This method will return impl Display for str {
// ...
#[inline]
fn as_str_slice(&self) -> Option<&str> { Some(self) }
} Now, here's where the magic lies. In impl<T: Display + ?Sized> ToString for T {
fn to_string(&self) -> String {
match self.as_str_slice() {
Some(s) => s.to_owned(),
None => // as before
}
}
} Since Thoughts? I guess it's a bit icky having an extra method there, but if we hide it from the docs it should be unobtrusive enough. |
Okay, so I prototyped my idea. Initial benchmarks look very promising, with There's a problem though with smart pointer types, specifically This decision should really be made on the type level, using either associated types or negative bounds. Unfortunately the associated types solution doesn't work yet (#20400), and negative bounds are still in the pipeline (rust-lang/rfcs#586). So I guess we'll have to wait. |
Borrowing a pointer out of an |
Ah, I stand corrected! That makes my solution practical, though it still feels like a hack. I guess if we treat this as a temporary solution, to be removed when negative bounds land, it should be okay. |
cc me |
Is this still relevant/reproducible? |
Specialization has landed. This can be worked on now? |
Was this effectively fixed by #32586? |
It should have been, yes! |
…xrvu feat: Implement diagnostics pull model
In a lot of rust code, I see
"".to_string()
being used as the default method of creating a new string. This would normally be fine, but it's actually noticeably slower thanString::new()
because it goes through the formatting infrastructure.It'd be nice if this pattern could be special-cased in
String::to_string
's implementation, or the optimizer made to do this transformation better.The text was updated successfully, but these errors were encountered: