The C++ version is taking a compile and runtime short cut by using printf instead of iostream. This pull request has timings with this changed: https://github.com/atilaneves/pythagoras/pull/1#issuecomment...
Comparing Pythagorean triples in C++, D, and Rust
31–40 of 118 posts
Re: Comparing Pythagorean triples in C++, D, and Rust
#32Earlier quoted context omitted.
I think the problem is flushing, not locking. Rust println!() flushes after each call, whereas more C-like io libraries flush once on program exit. Big difference in the number of system calls.
EDIT: THIS IS ALL WRONG AND BACKWARDS, SEE BELOW -------------------------- > 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 http…
pub struct Stdout {
inner: Arc>>>>,
}
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...
Re: Comparing Pythagorean triples in C++, D, and Rust
#33 CT = compile time
RT = run timeRe: Comparing Pythagorean triples in C++, D, and Rust
#34Earlier quoted context omitted.
EDIT: THIS IS ALL WRONG AND BACKWARDS, SEE BELOW -------------------------- > 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 http…
Are you sure about this? AFAIK, println! uses io::stdout(), which is defined like so: pub struct Stdout { inner: Arc >>>>, } 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 t…
thank you
Re: Comparing Pythagorean triples in C++, D, and Rust
#35Re: Comparing Pythagorean triples in C++, D, and Rust
#36Earlier quoted context omitted.
> 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. 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.
Yeah, I tried the locking version and didn't see a noticeable improvement.
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.
Re: Comparing Pythagorean triples in C++, D, and Rust
#37If there are big differences in where you don't expect them (e.g. printf in a for loop being very slow), then it usually is a difference in implementation and possibly contract. E.g. I wouldn't be surprised if println! in Rust is synchronous, which tends to be slow on both terminals and redirections (i.e. file I/O). For these simple examples an strace may be enlightening in this regard. Edit: Indeed this seems to be…
Re: Comparing Pythagorean triples in C++, D, and Rust
#38I would be really interested to know where the overhead in the simple rust version comes from. At first I thought it might be the println() being less efficient for whatever reason, but even without that line this[1] takes 300ms, compared to 184ms for this[2] (with the printf!). 1. https://raw.githubusercontent.com/atilaneves/pythagoras/mast... 2. https://raw.githubusercontent.com/atilaneves/pythagoras/mast...
Someone found a single character change providing a 2x speedup: https://www.reddit.com/r/rust/comments/ab7hsi/comparing_pyth...
“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.”
Re: Comparing Pythagorean triples in C++, D, and Rust
#39Re: Comparing Pythagorean triples in C++, D, and Rust
#40Those of us who have compute-bound workloads (scientific simulations in my case, but this often comes up in gamedev and elsewhere) often complain about how unusably slow debug builds impede our workflow in C++. One fairly common solution to this in extreme cases is sticking to a mostly C-like subset of the language or just using C. I don't have much experience with Rust, but judging by the results here, debug builds…