Comments (7)
The problem with your desired optimization, @Jerrody, is ultimately because of this program:
// pointer-escape-kinda.rs use std::{error, ptr}; #[derive(Debug)] struct MoveArray<T, const N: usize>([T; N]); #[inline(never)] pub fn main() -> Result<(), Box<dyn error::Error>> { let place_0 = MoveArray::<i32, 3>([1, 2, 3]); let ptr = ptr::addr_of!(place_0) as *mut i32; let place_1 = place_0; unsafe { ptr.write(5) }; println!("{:?}", unsafe { (ptr as *mut [i32; 3]).read() }); println!("{:?}", &place_1); Ok(()) }Note that I do something that one might normally consider "impossible": mutate an immutable location. Indeed, if you run it via Tools -> Miri, Miri will complain about it being UB, currently. This being true makes some other semantics harder to implement, so whether this should be permitted is considered an open question in Rust's operational semantics:
It's not implausible, though, due to the fact you derive the pointer from
&Vec<i32>
, which has less questions than theptr::addr_of!
I just used.
Thanks for the explanation. Sorry that I'm dumb in understanding these things, thanks for patient.
from rust.
Behaviour is the same in debug and release.
Code
fn main() { let vec1 = vec![1, 2, 3]; println!("{:p}", &vec1); let vec2 = vec1; println!("{:p}", &vec2); }Output
0x7ffe2bd06e90 0x7ffe2bd06e70
This is just waste of CPU time on performing this machinery, where basically changes only identifier.
Do you have a version of this that does not require printing the pointer values?
Consider this Godbolt: https://rust.godbolt.org/z/79vGhfcMv
I refer to your code as "print-move-print.rs".
I offer these alternatives, one where we "move" the vec and print the new address twice:
// print-after-move.rs
#[inline(never)]
pub fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec1;
println!("{:p}", &vec2);
println!("{:p}", &vec2);
}
And one where we keep the vec in the same variable and print its address twice:
// stay-printing.rs
#[inline(never)]
pub fn main() {
let vec2 = vec![1, 2, 3];
println!("{:p}", &vec2);
println!("{:p}", &vec2);
}
The last is essentially the "optimized form" that you would want. Note the diff views, that show that the two alternatives I offer are considered equivalent.
It may be hard to follow all the assembly, but note that your version has this string:
sub rsp, 128
My versions have this string:
sub rsp, 96
That's the size of the stack allocation for locals... and is 32 bytes! ...or the size of a Vec and a reference. I believe your attempt to inspect the address is actually what is producing the deoptimization. I have advocated quite strongly for optimizing the resulting assembly output of Rust code based on move semantics and declaring UB any programs that try to futz with obtaining pointers by strange means, yet it is still not clear to me that this is a desirable optimization after someone prints the address?
from rust.
Behaviour is the same in debug and release.
Code
fn main() { let vec1 = vec![1, 2, 3]; println!("{:p}", &vec1); let vec2 = vec1; println!("{:p}", &vec2); }Output
0x7ffe2bd06e90 0x7ffe2bd06e70
This is just waste of CPU time on performing this machinery, where basically changes only identifier.Do you have a version of this that does not require printing the pointer values?
Consider this Godbolt: https://rust.godbolt.org/z/79vGhfcMv
I refer to your code as "print-move-print.rs".
I offer these alternatives, one where we "move" the vec and print the new address twice:
// print-after-move.rs #[inline(never)] pub fn main() { let vec1 = vec![1, 2, 3]; let vec2 = vec1; println!("{:p}", &vec2); println!("{:p}", &vec2); }And one where we keep the vec in the same variable and print its address twice:
// stay-printing.rs #[inline(never)] pub fn main() { let vec2 = vec![1, 2, 3]; println!("{:p}", &vec2); println!("{:p}", &vec2); }The last is essentially the "optimized form" that you would want. Note the diff views, that show that the two alternatives I offer are considered equivalent.
It may be hard to follow all the assembly, but note that your version has this string:
sub rsp, 128My versions have this string:
sub rsp, 96That's the size of the stack allocation for locals... and is 32 bytes! ...or the size of a Vec and a reference. I believe your attempt to inspect the address is actually what is producing the deoptimization. I have advocated quite strongly for optimizing the resulting assembly output of Rust code based on move semantics and declaring UB any programs that try to futz with obtaining pointers by strange means, yet it is still not clear to me that this is a desirable optimization after someone prints the address?
What I would expected in this situation is keeping same pointer to the Vec, instead Rust creates copy of that pointer that points to the Vec. I understand that this example is simple and trivial, but in big applications can happen many moves and this is, little, but unnecessary copy that CPU does, but in reality it can just do nothing and ownership isn't violating, just changes identifier.
from rust.
@Jerrody Please examine my examples again.
The optimization you describe already occurs, but not if you print out the address.
from rust.
@Jerrody Please examine my examples again.
The optimization you describe already occurs, but not if you print out the address.
Alright, another question, why it happens that if I print an address before move and after move then I get different address. I already understood that we get this optimization, but in my example, why it's different.
from rust.
What jublee is saying is that by trying to observe how the program behaves (printing the addresses) you're altering its behavior. If you don't print the addresses then multiple uses of vec do optimize.
Here's a simpler version with lots of moves: https://rust.godbolt.org/z/Y9xo64o57.
This does optimize, even at opt-level 0!
If we add something that takes a reference but does not leak its address bits then the moves still optimizes away: https://rust.godbolt.org/z/bM8vPc5Ea
The extra mov instrunctions in the assembly are just the length getting black-boxed, not the vec being moved.
I already understood that we get this optimization, but in my example, why it's different.
Printing the address means the address bits now become observable program behavior.
Behavior that is not observable¹ can be modified or eliminated by the optimizer under the as-if rule. Which means that not printing the address gives the optimizer more freedom.
¹according to the language specification, things like debuggers do not count
from rust.
The problem with your desired optimization, @Jerrody, is ultimately because of this program:
// pointer-escape-kinda.rs
use std::{error, ptr};
#[derive(Debug)]
struct MoveArray<T, const N: usize>([T; N]);
#[inline(never)]
pub fn main() -> Result<(), Box<dyn error::Error>> {
let place_0 = MoveArray::<i32, 3>([1, 2, 3]);
let ptr = ptr::addr_of!(place_0) as *mut i32;
let place_1 = place_0;
unsafe { ptr.write(5) };
println!("{:?}", unsafe { (ptr as *mut [i32; 3]).read() });
println!("{:?}", &place_1);
Ok(())
}
Note that I do something that one might normally consider "impossible": mutate an immutable location. Indeed, if you run it via Tools -> Miri, Miri will complain about it being UB, currently. This being true makes some other semantics harder to implement, so whether this should be permitted is considered an open question in Rust's operational semantics:
It's not implausible, though, due to the fact you derive the pointer from &Vec<i32>
, which has less questions than the ptr::addr_of!
I just used.
from rust.
Related Issues (20)
- Potential overflow in the calculation of complex trait bounds involving tuples HOT 1
- TAIT: type parameter `impl FnOnce()` is part of concrete type but not used in parameter list for the `impl Trait` type alias HOT 4
- Weird diagnostic for recursion in const fn HOT 1
- Struct update syntax doesn't reborrow mut references HOT 4
- panic during codegen/LLVM phase HOT 2
- ICE: `relating different kinds` HOT 2
- ICE: `Tried to make Ignore indirect` HOT 1
- Bad codegen using `u16::to/from_be_bytes` HOT 1
- `struct` documentation should include `Sized` in the listed auto trait implementations HOT 2
- Bootstrap is slow HOT 3
- UpperHex formatting might panic HOT 3
- Repeated spurious rustdoc test failure: rustdoc-gui/help-page HOT 1
- Panic when setting RUST_MIN_STACK incorrectly HOT 3
- Docs produce invalid type when using bounds in associated type position HOT 1
- `unnameable_types` should show where the type is reachable HOT 2
- MIR_borrow_checking and MIR_effect_checking are very slow HOT 2
- Bevy segfaults on some Windows systems after Rust 1.79 update HOT 24
- ICE with generic_const_exprs (and std::simd)
- recommending the wrong Arbitrary
- Complete tier 3 target information HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rust.