Repository: rust
Issue: function performance seems to be affected by a match arm which is not evaluated. 
Labels: I-slow,C-discussion

so I am very new to rust and perhaps missing a trick here but I figured I will raise the question here because I am puzzled by this behavior.

I have a function lets call it serialize which takes a slice of u8 bytes and writes it to the u8 fixed size array allocated on stack. Because the pre-allocated fixed size array can over flow I have to do a check in the function prior to writing if there are enough bytes available on that stack allocated array. In my bench mark I then check performance of this serialize function and I know that in the scenario I had setup there is always sufficient room to write into. However, I have to do a mach to test for this and it seems that some of the code in the match arm which is never executed still gets evaluated.


Here is the actual function, so essentially it seem that the format! block of the first match arm is affecting performance characteristics of the function. If I for example simply add panic! on top of Result::Err I get 2x performance improvement and the bench completes with out panicking. I get similar effect If I simply put a empty string into the format! macro like so format!("") what am I doing wrong?

Is format! macro gets expanded into something outside of the match arm? and always runs regardless of the condition ?

```rust
    pub fn serialize_bytes(&mut self, bytes: &[u8]) -> Result<&mut Self> {
        let input_len = bytes.len();
        let avail = self.avail();
        match input_len > avail {
            true => {
                // panic!("blah"); // TODO this also seems to improve the bench mark which is technically never evaluating panic!
                Result::Err(SerDeError {
                    message: format!(
                        "adding {input_len} bytes, {avail} slots available. input: {bytes:?} buffer: {self:x}",
                    ),
                })
            }
            false => {
                // T.serialize(&serializer) - reuse serializer each iter
                //         time:   [62.164 ns 64.446 ns 67.565 ns]
                // self.bytes[self.len..self.len+input_len].copy_from_slice(&bytes);
                // 50% improvement using unsafe
                // T.serialize(&serializer) - reuse serializer each iter
                //         time:   [29.611 ns 30.166 ns 30.881 ns]
                unsafe {
                    std::ptr::copy_nonoverlapping(
                        bytes.as_ptr(),
                        self.bytes.as_mut_ptr().add(self.len),
                        bytes.len(),
                    );
                }

                self.len += bytes.len();
                Result::Ok(self)
            }
        }
    }
```

- bench mark results  with format! of blank string even thought this march arm is never executed. performance is similar to when simply adding panic! on top of the Result::Err(...

``` 
                Result::Err(SerDeError {
                    message: format!(
                        "",
                    ),
                })

to_serializer           time:   [14.396 ns 15.042 ns 15.750 ns]
                        change: [-65.368% -63.455% -61.474%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
```

- bench mark results with format! that has to expand a number of variables, however this match arm is not evaluated under the test scenario
```

                Result::Err(SerDeError {
                    message: format!(
                        "adding {input_len} bytes, {avail} slots available. input: {bytes:?} buffer: {self:x}",
                    ),
                })

to_serializer           time:   [34.094 ns 34.780 ns 35.582 ns]
                        change: [+137.94% +149.42% +161.38%] (p = 0.00 < 0.05)
                        Performance has regressed.
```