TL;DR: No, there is no difference in performance (in the question example and other observation operators) when you compile with the option release.
The arithmetic operations in std::ops
are defined through traits, for example, the sum operation:
#[doc(alias = "+")]
pub trait Add<Rhs=Self> {
/// The resulting type after applying the `+` operator.
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
/// Performs the `+` operation.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn add(self, rhs: Rhs) -> Self::Output;
}
The function add
receives 2 parameters of the same type (Rhs=Self
) and returns a result of the same type, too.
The implementation for the primitive types (usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64
) are defined in the macro add_impl
:
impl Add for $t {
type Output = $t;
#[inline]
#[rustc_inherit_overflow_checks]
fn add(self, other: $t) -> $t { self + other }
}
That is, it implements the sum through the operator itself +
and, as there is the attribute #[inline]
, the compiler in mode release, optimizes the code and does not generate none performance difference.
Reference: https://github.com/rust-lang/rust/blob/master/src/libcore/ops/arith.rs
If you store the code in the mode debug (without any optimization), there is a small difference in the generated binary code that results in loss of performance.
To the code below:
use std::ops::{Add};
// Lê uma string numérica digitada pelo usuário e converte para inteiro de 64 bits
fn get_number() -> i64 {
let mut buf = String::new();
std::io::stdin().read_line(&mut buf).unwrap();
buf.trim().parse::<i64>().unwrap()
}
// Função principal
fn main() {
let x = get_number();
let y = get_number();
let opsadd = x.add(y); // Soma através do método add
let diradd = x + y; // Soma direta
println!("Direto: {}", diradd);
println!("Ops: {}", opsadd);
}
Without optimization, it generates a call in the executable (call) to the function add
to obtain the result and store in opsadd
and, for the diradd
the sum is made directly without calls.
This call is required because the function is compiled without the [inline] in the mode without optimization:
140002a20: 48 81 ec 28 01 00 00 sub $0x128,%rsp
140002a27: e8 c4 fe ff ff callq 0x1400028f0 ; lê entrada do usuário
140002a2c: 48 89 44 24 68 mov %rax,0x68(%rsp) ; salva em x
140002a31: e8 ba fe ff ff callq 0x1400028f0 ; lê entrada do usuário
140002a36: 48 89 44 24 70 mov %rax,0x70(%rsp) ; salva em y
140002a3b: 48 8b 4c 24 68 mov 0x68(%rsp),%rcx
140002a40: 48 8b 54 24 70 mov 0x70(%rsp),%rdx ; Carrega os 2 valores e...
140002a45: e8 b6 ed ff ff callq 0x140001800 ; ...chama o add
140002a4a: 48 89 44 24 78 mov %rax,0x78(%rsp) ; salva o resultado em opsadd
140002a4f: 48 8b 44 24 68 mov 0x68(%rsp),%rax ; obtém o valor de x
140002a54: 48 03 44 24 70 add 0x70(%rsp),%rax ; soma direto (+) com y
140002a59: 0f 90 c1 seto %cl
140002a5c: f6 c1 01 test $0x1,%cl
140002a5f: 48 89 44 24 60 mov %rax,0x60(%rsp) ; salva o resultado em diradd
140002a64: 0f 85 51 01 00 00 jne 0x140002bbb
With optimization, the sum is made directly and the compiler, including, "understands" that the value of opsadd
and diradd
are the same:
1400014b0: 56 push %rsi
1400014b1: 57 push %rdi
1400014b2: 48 83 ec 78 sub $0x78,%rsp
1400014b6: e8 d5 fe ff ff callq 0x140001390 ; lê entrada do usuário
1400014bb: 48 89 c6 mov %rax,%rsi ; salva em x
1400014be: e8 cd fe ff ff callq 0x140001390 ; lê entrada do usuário
1400014c3: 48 01 f0 add %rsi,%rax ; já soma direto com y
1400014c6: 48 89 44 24 38 mov %rax,0x38(%rsp) ; salva o resultado em opsadd
1400014cb: 48 89 44 24 40 mov %rax,0x40(%rsp) ; salva o mesmo resultado em diradd
Therefore, without optimization there is an operation of call
"", which generates a cost of performance during execution and, with optimization, this cost does not exist.
Understood I thought there would be some difference , for example in extensive calculations as an integral or derivative I thought that using these resources there would be an optimization.
– Lucas Palomo
I also noticed that the Boolean operators in the Std::ops modules like < , > , &&, || , != etc... The same case would then be valid :)
– Lucas Palomo
Yes, it is valid yes for boolean operators, which follow the same logic
– Gomiero