7 ms·
> As of this writing, the 3rd fastest submission is written in Rust and produces out at a rate of 3 GB/s, 2nd is written in C and produces at a rate of 41 GB/s
by sillysaurusx 5y ago
> As of this writing, the 3rd fastest submission is written in Rust and produces out at a rate of 3 GB/s, 2nd is written in C and produces at a rate of 41 GB/s and the fastest is written in Assembler and produces at a rate of 56 GB/s.
This makes me happy. The order is exactly as it should be, much to the disappointment of the Rustaceans.
It's a nice reminder that for the ultimate performance, there is no substitute for knowing exactly what the assembler is doing.
It's also a nice reminder that most of us will never want to do that.
EDIT: Whoa. It's late, and I thought Rust was at 30 GB/s instead of 3, i.e. roughly neck and neck with C. I meant to make a good-natured joke. There must be something wrong with the Rust implementation to be 10x slower; I wonder what it is.
As I mentioned further down in the comments, I'll donate $500 to Watsi if someone manages to displace the C implementation in Rust or any other language besides C/C++/ASM. Be sure to DM me on Twitter (https://twitter.com/theshawwn https://twitter.com/theshawwn) if you do, both so I'll see it and so that I can congratulate you. I'm sure it's possible, but it's sort of interesting that the activation energy is so high.
- gopiandcode 5y agoYou're totally right. I think a lot of rust developers are going to be absolutely distraught that rust isn't the fastest language for writing fizzbuzz programs. I guess they're just going to have to settle with rust being the best language to write safety-critical high performance concurrent low-level code.
- GrayShade 5y agoYou do seem to have an axe to grind with the people using Rust. I don't see any reason why the same thing [1] could not be implemented in Rust. EDIT: I got caught by an off-by-one there, the second fastest solution (doing JIT compilation) is actually [2]. [1]: https://codegolf.stackexchange.com/a/215231 https://codegolf.stackexchange.com/a/215231 [2]: https://codegolf.stackexchange.com/a/236737 https://codegolf.stackexchange.com/a/236737
- sillysaurusx 5y agoMuch like speedruns, it's up to you to prove it :) I just enjoy dosing the Rusties with reality every so often. If you write a Rust version that can beat the C version, I'll donate $500 to Watsi. Good luck!
- KingOfCoders 5y ago"I just enjoy dosing the Rusties with reality every so often." Aka troll.
- AnIdiotOnTheNet 5y agoNot necessarily. Language evangelists can be incredibly annoying... actually, evangelists in general can be really annoying. It is cathartic to prove annoying people wrong every once in a while.
- Ygg2 5y agoOtoh. Being a dick, to majority of people because of acts of minority is worse.
- GrayShade 5y agoI don't know. I use Rust myself, but I've seen more people complaining about Rust evangelism than people actually doing that. The RESF is a bad meme.
- colejohnson66 5y agoWhen there's a memory related bug (or CVE) in a program written in C or C++, there's almost always some comment about how the Rust compiler would've caught it
- KingOfCoders 5y agoFrom Rust developers or from app users? As an app user I would prefer if apps are written in Rust and Im reminded with every CVE for a C program.
- bartvk 5y agoIt's not just knowing exactly what the assembler is doing, but also what the kernel is doing (but maybe you also meant this). "This implementation only supports Linux", and then continues about the use of a bunch of system calls: * "asks the Kernel to defragment the physical memory it's using via the madvise system call" * "use 2 MB of RAM each even though neither need 2 MB. This keeps the page table orderly" * "Most competing FizzBuzz implementations call the write system call which can lead to data needing to be copied between user and Kernel space. So vmsplice is used instead." And then the most fascinating bit: "The CPU's L2 cache is split into two halves, one for calculating the output of FizzBuzz, the other storing the result of the last calculation batch. This means there is no need to use any slower L3 memory operations." "Slower L3 memory operations", I've not read that sentence before :D
- MayeulC 5y ago> the most fascinating bit It is really fascinating, but I disagree a bit with your pick :) To me, the most fascinating part is using a bytecode interpreter. It makes perfect sense, it's basically optimizing the code size to fits in the cache. It's also a bit like defining a whole new instruction set dedicated and optimized for Fizzbuzz! I think the approach was a bit similar to a VLIW https://en.wikipedia.org/wiki/Very_long_instruction_word https://en.wikipedia.org/wiki/Very_long_instruction_word where a single 32 bits word is loaded and interpreted at a time. Most of the state of the Fizzbuzz program is encoded in this bytecode. > "Slower L3 memory operations", I've not read that sentence before You hear it all the time when trying to optimize for speed in a hot loop. Keep your data structures in a way that fits in the cache. Align your data with cache boundaries. Code needs to be small too, hence the bytecode approach. This is also the reason why you can't unroll loops too much. If your implementation does not need to fetch (or write) data from(/to) higher levels of the memory hierarchy, you'll see tremendous gains. There's even this bit in the original source: "while waiting for writes to go through to the L2 cache" :) There are a few more very interesting hacks, such as the "high-decimal" format that skips the "need to do binary/decimal conversions."
- lawn 5y agoSo you think that it's expected that C is 10 times faster than Rust?
- sillysaurusx 5y agoWow. Perhaps I should be embarrassed, but I mentally filled in "30 GB/s" instead of 3 GB/s. I thought Rust was mostly neck and neck with C. I see now why a lot of fellows responded in a defensive way. What's it doing to be so much slower? That's shocking. I may not enjoy Rust, but I do respect its ability to approach C++ performance.
- Arnavion 5y agoAt the very least, the itoap crate being used there does divisions by and comparisons to powers of 10 as part of stringifying integers, which the C and ASM versions don't seem to be doing. A crate with a function for stringifying arbitrary integers cannot take advantage of the fact that it's going to be used for stringifying consecutive integers, as an inlined solution can.
- deleted 5y ago[deleted]
- IshKebab 5y ago> That's shocking. Not really. This is a hyper optimised microbenchmark. The actual work being done is so trivial that any "overhead" is really significant and you can get order of magnitude speedups by doing arcane things with caches, eliminating tiny inefficiencies and so on.
- xxpor 5y agoComplete speculation, but I think you'd find that's true for most problems. Very little CPU time is spent on the business logic, and the rest is overhead.
- misja111 5y agoAs far as I understand, that #2 C program contains hardly any C code but mostly inlined assembly.
- Arnavion 5y ago>It's a nice reminder that for the ultimate performance, there is no substitute for knowing exactly what the assembler is doing. I didn't realize viewing the assembly of a compiled binary was something reserved for C. Someone should tell rust.godbolt.org that it's not supposed to exist.
- samhw 5y agoI think their point is that C is sufficiently close to assembler that you know exactly what assembly any given line of C will produce. This is an old canard which is not really true (https://zenhack.net/2015/08/02/c-is-not-portable-assembly.html https://zenhack.net/2015/08/02/c-is-not-portable-assembly.ht...), but it's common among people who derive a sense of identity from writing C.
- dahfizz 5y agoGo read the second place C entry[1]. Its a JIT for assembly code. [1] https://codegolf.stackexchange.com/questions/215216/high-throughput-fizz-buzz/#answer-236737 https://codegolf.stackexchange.com/questions/215216/high-thr...
- bonzini 5y agoThe second one (written by me) is actually JIT-compiled assembly. So little of the runtime is spent in the C code that -O0 vs -O3 makes no difference at all; and even if you wrote the glue code in Python it would not be much slower than the C code. Also the third entry is not the one in Rust. It's just that the Rust entry came later and thus was not included in the plot. The third entry is https://codegolf.stackexchange.com/a/215236/56694 https://codegolf.stackexchange.com/a/215236/56694; it is also C. > displace the C implementation in Rust or any other language besides C/C++/ASM This is not a language contest, it's an algorithmic contest: that is, it's the best algorithm that wins, not the best compiler. The top entry, converted into C or Rust by mostly menial work, would probably be only a few % slower and would displace the C implementation.
- stavros 5y agoNow I'm kind of hoping that someone will rewrite the glue in Python so that Python is the second fastest implementation of them all, just for the laughs.
- sillysaurusx 5y agoI would love to see a Python implementation that approaches the C code. It would be educational on so many levels. Would anyone be interested in trying? Also, why is the ASM version so much faster if the glue code doesn't make much difference? I suppose it matters at the margins...
- bonzini 5y ago> why is the ASM version so much faster if the glue code doesn't make much difference The remark on the glue code only applies to my entry (the second). The assembly entry uses a completely different (and much more complicated) algorithm than the C entry.
- hectormalot 5y agoIf you read the description you’ll see that it’s optimizing around certain syscalls like memcopy (which is otherwise limiting and reduces speed by 5x). I think it’s less language choice, and more low level optimization that is making a difference here. (To check, I wrote a Go program that doen nothing else than fmt.Print($largebody) in a for loop and it tops out at around 10GB/s)
- yodelshady 5y agoFYI, on my machine a naive Rust implementation (modulo plus println!) runs at the same speed as a naive Python implemention (16-17 MB/s), even compiled with --release. Naive C manages 160-170 MB/s. (And I fully admit the naive implementations are pretty much as far as I'm going with this). I would guess it's the println! macro eating the time.
- pcwalton 5y agoIt's probably stdout locking. Call Stdout::lock.
- yodelshady 5y agoedit: weirder, naive Julia (1.7 on Linux) is terrible. 45 KB/s. Ruby is slightly slower than Python or Rust, 11 MB/s. I was expecting Python to be slowest among the interpreted languages, apparently not. Pypy yields a speedup to 70 MB/s. Summing naive implementations (for each i: start with empty string, append fizz/buzz based on the modulus of each, then conditionally append i and print): Julia 45 KB/s Ruby 11 MB/s CPython 15 MB/s Rust 16 MB/s Pypy 70 MB/s C 160 MB/s
- sc11 5y agoDo you mind sharing the Julia code? Seems odd that it's that far away from even Python.
- adgjlsfhk1 5y agoby default Julia uses locking for writes to guarantee thread safety when multiple writes are happening. That said, it's totally possible to go way faster using buffered IO.
- yodelshady 5y ago``` for i = 1:typemax(UInt64) s = "" if i % 3 == 0 s = s * "fizz" end if i % 5 == 0 s = s * "buzz" end if s == "" s = string(i) end println(s) end ``` Measured over 10 s after a 10 s burn-in period, Julia 1.7 on Ubuntu 21.10.
- pcwalton 5y agoYou can basically take any LLVM IR that Clang would produce and produce Rust that compiles down to it (modulo irreducible control flow, I think, but the C++ doesn't have that). Because of that, C++ vs. Rust language (as opposed to library) performance comparisons are uninteresting. > It's a nice reminder that for the ultimate performance, there is no substitute for knowing exactly what the assembler is doing. C and C++ do not let you know exactly what the assembler is doing. I work on compilers for a living and despite that--perhaps because of that--I have no confidence that I can predict what instructions the compiler will generate ahead of time. If I need to know the actual instructions, I run my code through Godbolt and check. C, C++, and Rust are all millions of lines of LLVM optimization passes away from the metal. Based on some other comments, I suspect that all the time is being spent in locking stdout, which you can amortize by using Stdout::lock [1]. As is so often the case when microbenchmarks are discussed online, this has nothing to do with the language. Also, it shouldn't need to be said, but FizzBuzz is so totally unrepresentative of real workloads that you shouldn't draw any conclusions about language performance from it. [1]: https://doc.rust-lang.org/stable/std/io/struct.Stdout.html#method.lock https://doc.rust-lang.org/stable/std/io/struct.Stdout.html#m...
- parhamn 5y ago> LLVM IR that Clang would produce You most certainly can’t unless your code is unsafe and in that case the comparison isn’t so interesting anymore.
- Aissen 5y agoIt is very interesting if you have properly verified invariants and you can guarantee (with manual checking) that your code is correct. It's an order of magnitude harder than just letting the borrow checker do its job, but it's entirely possible (just like in any other language).
- KingOfCoders 5y ago"disappointment of the Rustaceans." I'm using Rust and I'm not dissappointed. Why should I? But I do appreciate how you create imaginary people in your head, troll them and mentally pad yourself for doing so.
- isoprophlex 5y agoAll the rust users rising to the bait in this thread sure aren't imaginary
- KingOfCoders 5y agoWhat comment comes to your mind of a Rust developer who thinks Rust is faster than C and needs a dose of reality?
- colejohnson66 5y agoRust is a memory safe systems programming language. As a systems programming language, it can be used in the same areas that C can (see Redox OS). I've seen quite a few Rust users online that have claimed that, because of that, it can be just as fast as C.
- KingOfCoders 5y agoWhat is the opinion of Golang users on this?
- politician 5y agoThis is really cool. It should be obvious that a few thousand hand-rolled assembly opcodes targeting a fixed architecture would win the race. If the size of the solution grew a couple of orders of magnitude larger though, I'd expect that the micro optimization challenge would overwhelm the author and compilers would be more competitive. Is the Table of Contents of your upcoming book public?
- tester34 5y ago>This makes me happy. The order is exactly as it should be, much to the disappointment of the Rustaceans. Why it makes you happy? it's a reminder how much we're losing performance, energy and stuff when we're writing in safe/expressive/easy to use languages like Java, C#, Python yada yada
- deleted 5y ago[deleted]
- jedimastert 5y ago> Rustaceans Completely off topic, but suddenly all of the crab branding makes a ton more sense
- deleted 5y ago[deleted]