1. https://raw.githubusercontent.com/atilaneves/pythagoras/mast...
2. https://raw.githubusercontent.com/atilaneves/pythagoras/mast...
1. https://raw.githubusercontent.com/atilaneves/pythagoras/mast...
2. https://raw.githubusercontent.com/atilaneves/pythagoras/mast...
“I believe the problem with ..= is that x..(y + 1) is not identical with x..=y. They are nearly equivalent on most values for x and y, except when y == i32::max(). At that point, x..=y should still be able to function, while x..(y + 1) is allowed to do nothing.”
As a C programmer, that sort of feels like cheating ;)
(safe) Rust does not claim to make your code correct, it claims that it will not have undefined behavior.
We do care about helping you make your code correct; it will check for overflow and panic at runtime in debug builds. But it's a secondary concern. Memory safety is hard enough!
I have no idea why LLVM misses optimizing this in Rust's case. Likely it is fed much trickier IR. It also misses the optimization that it does in the C case of lifting the xx and zz multiplications to the appropriate loop level.
But I also note that the original version of your benchmark was calling `println!`, which means that you were essentially benchmarking high-level, thread-safe I/O. EDIT: Not in this case, see the thread below.
Some Rust benchmarking tips:
1. Always run `cargo build --release`. Debug builds are slow.
2. Be sure to use `stdin.lock()` or `stdout.lock()` when reading or writing standard I/O. If you don't, Rust has to lock standard I/O for you on each call. This means using `writeln!` instead of `println!`.
I don't think so. The program is only doing a thousand prints, which is far less than the total number of loop iterations. Try changing to locked stdout and writeln!---I doubt you'll notice a difference.
We do a lot of I/O intensive Rust at work, and I have a list of things to double-check when benchmarking. The most common slowdowns: debug builds, unlocked stdio, line iterators, and anything else which allocates in an inner loop.
If I can hit 250 MB/s throughput per core on my laptop, with some light data processing, I'm usually quite happy.
--------------------------
> Rust println!() flushes after each call,
To be clear, println! does not flush after each call.
Many terminals are line-buffered, and so when println! emits a \n, the terminal will flush. So, println! will probably cause a flush, but does not flush itself. println! is the exact same as `print!`, except for the additional printing of \n https://doc.rust-lang.org/stable/src/std/macros.rs.html#157-...
pub struct Stdout {
inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
}
In particular, it's specifically using LineWriter internally, which does flush whenever it sees a `\n`.println! does not itself explicitly flush, but its current implementation does guarantee that it will. However, I don't think this is an API guarantee. In the definition of Stdout, there is this FIXME:
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
Which basically means that someone thought its buffering strategy should be determine by whether or not stdout is connected to a tty. This is what ripgrep does for example, but I had to build out my own infrastructure to do it: https://docs.rs/grep-cli/0.1.1/grep_cli/#coloring-and-buffer... --- Arguably, io::stdout() should do the same.I don't think buffer configuration at the level of the terminal plays a role here. This is somewhat confused by programs like stdbuf[1] which purport to enable users to change the buffering strategy used by a program in their shell. But in reality, it appears tightly coupled with C's FILE data type and perhaps even tightly coupled with glibc itself? I'm not sure.
[1] - https://www.gnu.org/software/coreutils/manual/html_node/stdb...
thank you
I just thought I'd confirm that it does not. The 'line buffering' of `tty`s applies to the input to the `tty` (IE. the keyboard) before it goes to the program - basically, the kernel will buffer characters you typed and not send them to the running program until you hit the `eol` character. On the output side the kernel just handles characters as they come in without any buffering/waiting.