4 ms·
A specific finding from this research is on the front page: https://news.ycombinator.com/item?id=20944403 https://news.ycombinator.com/item?id=20944403 Rust w
by chrisaycock 7y ago
A specific finding from this research is on the front page:
https://news.ycombinator.com/item?id=20944403 https://news.ycombinator.com/item?id=20944403
Rust was found to be slightly slower than C because of bounds checking, which the compiler keeps even in production builds.
- mlindner 7y agoExcept their answer is wrong, because Rust (LLVM rather) does eliminate bounds checks. They're comparing GCC vs LLVM here more than they are comparing C vs Rust. They should have compiled their C code in LLVM. Their implementation is littered with uses of "unsafe" which means its almost impossible for the compiler to eliminate the bounds checks.
- gameswithgo 7y agollvm cannot always eliminate bounds checking and gcc vs llvm does not explain all of the difference
- csande17 7y ago> Their implementation is littered with uses of "unsafe" which means its almost impossible for the compiler to eliminate the bounds checks. Does `unsafe` actually impede optimization in this way? I thought it just disabled certain type checks and error messages but didn't affect anything on the LLVM level.
- dbaupp 7y agoYou're essentially right. The grandparent may be meaning that they're using a lot of raw pointers (which requires unsafe), and raw pointers means less aliasing information, and so less precise optimisations. This can affect bounds checks, because a raw pointer could potentially alias the length field of a slice or vector, and so LLVM has to be conservative around writes to them.
- leshow 7y agoAre their uses of unsafe necessary? After briefly looking over the implementation it seems like they could just be using references in a bunch of places. Take for example: let queue = &mut self.rx_queues[queue_id as usize]; rx_index = queue.rx_index; last_rx_index = queue.rx_index; for i in 0..num_packets { let desc = unsafe { queue.descriptors.add(rx_index) as *mut ixgbe_adv_rx_desc }; let status = unsafe { ptr::read_volatile(&mut (*desc).wb.upper.status_error as *mut u32) };
- dbaupp 7y agoI've got no idea. One would have to understand the code fairly deeply to tell that. For instance, are the volatile reads/writes meant to be atomic ones (which could be done safely) or are they truly volatile?
- GrayShade 7y agoThere's a per-packet bounds check here [1] which probably can't be eliminated by the compiler because it cycles over the array. I imagine that's noticeable. [1]: https://github.com/ixy-languages/ixy.rs/blob/master/src/ixgbe.rs#L175 https://github.com/ixy-languages/ixy.rs/blob/master/src/ixgb...
- ChrisSD 7y agoSo the bounds check is: queue.bufs_in_use[rx_index] If so the bounds check could possibly be safely eliminated by the programmer because I think `wrap_ring` ensures that rx_index will always be in bounds?
- GrayShade 7y agoYes. It wouldn't be too unidiomatic to use get_unchecked in those two places, perhaps with a debug_assert! in place. It would be really nice if this wasn't needed, but it's a valid use of unsafe code.
- edoloughlin 7y agoThey're comparing GCC vs LLVM here more than they are comparing C vs Rust That makes sense. Their table of CPU performance counters [1] shows way more instructions per cycle for Rust and way fewer L1 cache hits for C. https://github.com/ixy-languages/ixy-languages/blob/master/Rust-vs-C-performance.md#cpu-performance-counters https://github.com/ixy-languages/ixy-languages/blob/master/R...