-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Avoid many allocations for CStrings during codegen. #53161
Conversation
r? @estebank (rust_highfive has picked a reviewer for you, use r? to override) |
@bors try |
⌛ Trying commit 9ca04a1e0e052f3fa03248828c56b3148a643178 with merge 6d5276398f760025f61c4579a7c475fedd1b06bb... |
☀️ Test successful - status-travis |
@rust-timer build 6d5276398f760025f61c4579a7c475fedd1b06bb |
Success: Queued 6d5276398f760025f61c4579a7c475fedd1b06bb with parent 18925de, comparison URL. |
|
||
let str_plus_nul = concat!($s, "\0"); | ||
|
||
if cfg!(debug_assertion) { |
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 think this needs to be debug_assertions?
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.
It does. Good catch!
Results are in. Looks alright from the instructions view, not so sure otherwise. |
O right, this is going to be 8 byte aligned, not 4. Yeah, doing either 30 or 38 seems good. All in all, I'm not sure that the "gains" are worth the churn. cc @rust-lang/wg-compiler-performance |
Overall it seems like a slight improvement to me. I agree with the |
I'd feel more comfortable with somebody from @rust-lang/wg-compiler-performance doing the final review. It seems to me that the only outstanding task is changing the |
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.
Overall this looks good to me. I just had a few small pieces of feedback.
|
||
/// Declare a global value. | ||
/// | ||
/// If there’s a value with the same name already declared, the function will | ||
/// return its Value instead. | ||
pub fn declare_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> &'ll Value { | ||
debug!("declare_global(name={:?})", name); | ||
let namebuf = CString::new(name).unwrap_or_else(|_|{ | ||
bug!("name {:?} contains an interior null byte", name) |
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 think we should try to retain this bug reporting code. It was introduced in f1dabed and caught an issue as recently as June 23. I'd recommend SmallCStr::new()
returns an Option<SmallCStr>
with its internal unwraps()
moved back into the callsites.
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'd like to avoid moving the unwraps()
to the call site, since there are so many of them an you can't recover gracefully anyway. How about I change the unwrap()
in SmallCStr::new()
into a bug!()
with more useful information? Together with the backtrace that should point you to the right spot pretty quickly.
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.
That sounds good to me!
@@ -61,9 +59,7 @@ fn declare_raw_fn( | |||
ty: &'ll Type, | |||
) -> &'ll Value { | |||
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); | |||
let namebuf = CString::new(name).unwrap_or_else(|_|{ | |||
bug!("name {:?} contains an interior null byte", name) |
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.
Same here
@@ -214,9 +210,7 @@ pub fn define_internal_fn( | |||
/// Get declared value by name. | |||
pub fn get_declared_value(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> { | |||
debug!("get_declared_value(name={:?})", name); | |||
let namebuf = CString::new(name).unwrap_or_else(|_|{ | |||
bug!("name {:?} contains an interior null byte", name) |
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.
Same here
@@ -348,7 +349,7 @@ fn vec_slice_metadata( | |||
let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); | |||
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); | |||
|
|||
let member_descriptions = [ | |||
let member_descriptions = vec![ |
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.
This is now being allocated on the heap instead of the stack right? Is that what we want?
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.
Yes, because it allows to re-use the String
allocations when constructing the CString
for the name
field down the line. It should be a win overall since all the other MemberDescription
can't get around allocating anyway.
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.
If you want to go crazy, the LLVM C++ method we're using is called through a C wrapper that we define ourselves and uses a StringRef, which is a pointer/length pair and doesn't actually need a terminating nul byte. So you could get theoretically completely avoid CStr for the name (and possibly other places as well). Of course, if / when the DebugInfo stuff gets an official C API, we'd likely be back at using plain C strings.
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.
If you want to go crazy
I don't :P
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#[macro_export] |
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.
Please add a comment explaining what this macro does.
DHAT is a good tool for finding out which heap allocations matter. |
Thanks for the hint, @nnethercote, I'll add it to my tool chest. |
9ca04a1
to
b8529c6
Compare
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 |
b8529c6
to
7e1faee
Compare
Let's see if this works: |
✌️ @wesleywiser can now approve this pull request |
I've never done this before. Do I just need to say? @bors r+ |
📌 Commit 7e1faee8b0945929a11c075d6e53664fc76b6ba4 has been approved by |
👍 |
@bors r- Merge conflict. (🤔 bors isn't detecting any merge conflict recently...) |
7e1faee
to
f2ede4d
Compare
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 |
f2ede4d
to
88d84b3
Compare
Rebased. @bors r=wesleywiser |
📌 Commit 88d84b3 has been approved by |
Avoid many allocations for CStrings during codegen. Giving in to my irrational fear of dynamic allocations. Let's see what perf says to this.
☀️ Test successful - status-appveyor, status-travis |
unsafe { | ||
CStr::from_bytes_with_nul_unchecked(str_plus_nul.as_bytes()) | ||
} | ||
} |
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.
cc @oli-obk this really wants to be a static assert, heh.
Giving in to my irrational fear of dynamic allocations. Let's see what perf says to this.