Live data from Hacker News

Rust is now overall faster than C in benchmarks

benchmarksgame-team.pages.debian.net

431–440 of 445 posts

Re: Rust is now overall faster than C in benchmarks

#431

Earlier quoted context omitted.

I thought that was impossible because it breaks references when moving strings.

I don't see why this would happen. what problems are you envisioning? moves should leave the original object in a valid but unspecified state. that is, a move should not break a reference to the original object itself, but there are no guarantees as to what data it contains afterwards. in the case of a dynamically allocated string, the moved-from object would probably be empty. with SSO, a move is necessarily a copy,…

No, I think the requirement is that a reference to the actual string buffer must be kept valid when the string is moved. And that property breaks with SSO data, which is not placed in the dynamically allocated buffer - it is placed directly in the object struct (it's an optimization after all), which can't be moved.

EDIT: seems I was wrong, and SSO is allowed for std::string. A similar optimization is illegal for std::vector, though, for the reasons I gave above.

Re: Rust is now overall faster than C in benchmarks

#432

Earlier quoted context omitted.

So he's comparing the AVL tree he wrote himself to a B-tree optimized to death by someone else? Out of interest though, does he mention somewhere which actual implementation he used?

Yes, and I suppose that's some of the point: a performant library ecosystem is one hell of a feature.

It sure must be a nice feature - for fast results. Counterpoint, though. I barely used Rust, but when I wanted to play with the Xi editor I got to see the bad places that buying into such an ecosystem can get you to - places formerly pioneered by NPM. I had to download 100s of packages, (IIRC?) there were some build problems, all for something where I don't really see the value of noteworthy dependencies.

If you really need a Btree (like, if you want to make a fair benchmark for a presentation) then you'll absolutely find a reasonable implementation in C. After all, why would you need dependency management for something that should have 0 dependencies?

As an example of library data structures implemented in C - if you want, check out my Red-black tree (not a Btree): https://github.com/jstimpfle/rb3ptr/blob/master/rb3ptr.h . It's really easy to integrate into your project. I think the API (found in rb3ptr.h) is totally usable, and it might also be faster than what you can get with safe Rust - unless you can easily use intrinsically linked data structures in safe Rust.

Re: Rust is now overall faster than C in benchmarks

#433
post #362

Earlier quoted context omitted.

This is not true. Undefined behaviour can mean that ``` bool b; if (b) printf("1 "); if (!b) printf("2 "); ``` might print `1 2 `.

It's not like that is hard to fix, and modern compilers will flag uninitialized variables. Use your brain and use your tools. C is not really that hard for a large number of problem sets.

> It's not like that is hard to fix

In an embedded context, such bugs may be extremely costly to fix, if it's even possible.

> modern compilers will flag uninitialized variables

Reading uninitialized variables is one of the more easily prevented forms of undefined behaviour. As pjmlp points out, undefined behaviour in C/C++ programs is one of the major sources of security vulnerabilities in today's software.

Re: Rust is now overall faster than C in benchmarks

#434
post #423

Earlier quoted context omitted.

Your claims contradict my experience. One example: C re-write of a popular chess engine Stockfish (written in C++) is significantly faster (10%-30% depending on who measures it at which time and on what hardware). This is a piece of code which was already heavily optimized for many years as speed is critical for the engine's performance. One guy (although very talented one) re-wrote it in C and got the speed gains. A…

This is implausible on its face. If your new C program is faster than your old C++ program, then you may simply rename files from ".c" to ".cc". Then, you have two C++ programs, one faster than the other. If your custom hash table really is faster than any library you find, congratulations! Recoding its interfaces, without giving up any performance, you can make it available for use in other C++ programs. As one may…

>>If your new C program is faster than your old C++ program, then you may simply rename files from ".c" to ".cc". Then, you have two C++ programs, one faster than the other.

While C++ isn't an exact superset of C it's close enough but it's not the point. The debate is about how the languages are used. Otherwise you could always say "yeah, use inline assembly and don't use any abstractions with the exception of structs, pointers and arrays".

>>Available C++ hash table libraries have benefit of overwhelmingly more optimization attention than could be afforded on behalf of a single program, and they deliver that performance to all dependent programs.

They are also general purpose. When you have something specific to optimize you will always beat general solutions.

>>Every programming project is an exercise in practical economics: your strictly-limited available attention goes where you choose. The greater productivity of coding in a more powerful language frees up attention that may then be allocated to areas that would otherwise suffer neglect.

Sure. The debate is about what is faster though and then C++ is not faster than C but C is often faster than even slightly idiomatic C++ and much faster than C++ with all the modern features used frequently. You will get stuff done faster in a higher level language of course but that besides the point of debate which language is faster where performance matters.

>>Whatever amount of attention you devote to making code in a poor language work at all, you may spend a fraction of coding in a better language, and the balance on other beneficial uses, such as better performance.

I don't agree C is a poor language. It's quite a common view as well. A lot of people who are good at low level stuff prefer C to C++ because the language is simple, easy to read and easy to reason about. C is poor at some things, it's fantastic for others. I personally love the language and it's my choice for many weekend projects.

>>That the new program is faster than the old program reliably demonstrates that the old program was not so well optimized as you suggest. (Your comment elsewhere, that "the whole project uses only [a] minimal set of C++ features" reveals perhaps more than you intended.) One may surmise that the old program's authors spent more of their limited attention on its effectiveness at playing chess than the latter program's author needed to.

Stockfish is a big decade+ old and still heavily developed community project with tens of programmers contributing to it. A lot of attention was given to it and to optimizing specific parts of it. Still, it's written in C++ in usual (although still very minimal) style and there is cost to it.

>>That the third, assembly-language program is faster still demonstrates that the previous programs left performance on the table.

Well, my experience is that people good at assembly run circles around very good C/C++ programmers. I would go as far as to say that it's hard to take anyone who doesn't realize it seriously. There is just so many things you can't do in C/C++ even with today very smart compilers.

>>My experience is that it is not hard to double the speed of a typical program just by paying attention to cache and pipeline effects. Most likely, the asm coder just happens to know more about those effects, knowledge that could as well have been applied to the others. Most programs seem fast enough exactly until another, faster one comes along; then they are instantly slow.

You just don't get it. Stockfish is a program which depends on being fast. Making it fast is the number one priority. A lot of very smart people spent hundreds of hours optimizing small parts of it like the best way to generate chess moves in as few CPU cycles as possible, designing the hash table to minimize cache misses etc.

If you can make Stockfish 2x faster you would be considered the prophet of programming and your statues would be raised in cities around the world. Seriously, it's not some average random code which you can make faster applying concept you happen to see on front page of Hacker News. We are talking about the code where performance matters. All the people working on such code know a lot about all the concepts you mentioned because they apply them day to day.

Anyway, CFish, asmFish and Stockfish are all open source projects. You can find them on Github. You can ask the authors why they think their stuff is faster if you are curious about it. I mean maybe it's worthwhile to understand why someone chooses to do all the work to re-write a popular community project to C or asm. It's a lot of difficult work. They might know something you don't.

Re: Rust is now overall faster than C in benchmarks

#435

Earlier quoted context omitted.

The CPU will load less cache data with linear searches. This is because you will have less cache misses. Less cache misses == less loading from memory. With pointer-heavy data structures, you load more from memory, and most of the stuff you do load is useless.

A binary tree might require you to visit only O(log2(N)) of your data, while a linear array on average requires you to visit one half. How does that correspond to less loading from memory? Linear arrays are often faster, not because they require fewer memory loads, but because the cache has intelligence built in (the prefetcher) that loads some memory in advance even before the code requests it. That intelligence wor…

You need to look at the coefficients. Memory queries pull in 64 bytes of contiguous memory at a time (actually more with speculative prefetching). That extra data is used in a linear scan, but is mostly wasted when doing random access. You also have other bottlenecks with binary search, e.g. branch misprediction.

Yes, for large enough N, a BST easily beats linear search.

Re: Rust is now overall faster than C in benchmarks

#436

Earlier quoted context omitted.

A binary tree might require you to visit only O(log2(N)) of your data, while a linear array on average requires you to visit one half. How does that correspond to less loading from memory? Linear arrays are often faster, not because they require fewer memory loads, but because the cache has intelligence built in (the prefetcher) that loads some memory in advance even before the code requests it. That intelligence wor…

You need to look at the coefficients. Memory queries pull in 64 bytes of contiguous memory at a time (actually more with speculative prefetching). That extra data is used in a linear scan, but is mostly wasted when doing random access. You also have other bottlenecks with binary search, e.g. branch misprediction. Yes, for large enough N, a BST easily beats linear search.

> That extra data is used in a linear scan, but is mostly wasted when doing random access

You are shifting goalposts. What the parent poster said is that a linear scan will read more memory than a binary search, therefore it will cause more churn in the cache (assuming same cache policies, which I don't know is a safe assumption), therefore linear scan may actually be less cache friendly - given that you're not interested in the data in any other way besides for the scan - by way of putting other parts of the program whose data was pushed out of the cache at a disadvantage.

Implied was also that linear scan might actually result in a slower program, even if the scan itself might be faster than a binary search.

What you replied is "The CPU will load less cache data with linear searches", which I assume to be false, although I will be happy to learn that it's actually the case (for example because the CPU has a clever cache eviction policy, executing linear scans by streaming in memory into a small part of the cache instead of thrashing the whole cache).

Let's say we have an array of 200 4-byte ints. Let's do a linear array scan and on average will touch 100 of them (or about 7 cache lines). Now let's say we have each integer in its own linked node in a BST in a totally random memory location. We can expect to need about 7 steps as well (2^8 = 256 > 200), which is 7 cache lines. So about 200 is already a lower bound where BST is more efficient in terms of visited cache lines, even for a pessimistic inefficient data structure like this 4-byte integer example.

Re: Rust is now overall faster than C in benchmarks

#437
post #427

An unrelated rant about benchmarksgame. Has anyone noticed that the Python implementation of regex beats a lot of the Rust and C implementations? That’s because it uses the PCRE2 library (written in C) which it assumes is installed on the OS. Benchmarks are always artificial but this seems like a step too far: the benchmark hardly says anything about Python and is dependent on the OS environment having the right depe…

I wrote that program in the hope that it would better illustrate why some of the benchmarks on the site aren't very good since for some benchmarks the program performance is highly dependent on the libraries being used and not the programming language implementation itself. I know at least one person opened an issue regarding this on the site issue tracker at https://salsa.debian.org/benchmarksgame-team/benchmarksgam…

It is an excellent illustration of that issue! And a needful reminder, as long as the implementations being compared are allowed use of that strategy.

It would be interesting to see benchmark comparisons with somewhat more rigorous guidelines about what’s being compared, perhaps mandating the use of the same algorithm. That approach would introduce problems as well, like some languages benefiting more than others from the chosen algorithms. I think benchmarks are useful but the fact that they’re so often “flawed” or “misleading” may paradoxically mean that we need more of them so we can get a clearer view of the field.

Re: Rust is now overall faster than C in benchmarks

#438
post #423

Earlier quoted context omitted.

This is implausible on its face. If your new C program is faster than your old C++ program, then you may simply rename files from ".c" to ".cc". Then, you have two C++ programs, one faster than the other. If your custom hash table really is faster than any library you find, congratulations! Recoding its interfaces, without giving up any performance, you can make it available for use in other C++ programs. As one may…

>>If your new C program is faster than your old C++ program, then you may simply rename files from ".c" to ".cc". Then, you have two C++ programs, one faster than the other. While C++ isn't an exact superset of C it's close enough but it's not the point. The debate is about how the languages are used. Otherwise you could always say "yeah, use inline assembly and don't use any abstractions with the exception of struct…

I have measured abstraction overhead in C++ for 20+ years. It was significant in the early 2000s. It is zero today.

That does not mean C++ programs are necessarily fast: it has always been easier to write slow programs, in any language. It doesn't mean C programs must be slow: making a fast C program just takes a great deal more work, and time, than a fast program in modern C++, so the extra time taken has been wasted.

You are always free to waste your own time. Wasting your employer's time is often less defensible. In the fintech world, suggesting C as a way to speed up a C++ program would get you laughed out of the room, at best.

The common experience noted in the original page is that C++ programs are faster than C programs. We know why.

That the chess program was easy to transcribe to C demonstrates that it was not good C++ code -- which you also revealed yourself. Making a faster C program while transcribing an almost-C C++ program is no big trick.

I routinely speed up programs by 2x by changing only a few lines. A 10-20% improvement in a whole rewrite is a great waste of time. Translating to asm, moreso. I would call a 10-20% improvement negligible, and crediting it to C delusional.

Re: Rust is now overall faster than C in benchmarks

#439
post #317
post #143

Earlier quoted context omitted.

OK thanks, indeed Clang is able to generate better assembly using __restrict__. And -O3 generates the same assembly as -O3 -fstrict-aliasing (which is not as good as __restrict__). I wish there was a C/C++ compiler flag for treating all pointers as __restrict__. However I guess that C/C++ standard libraries wouldn't work with this compiler option (and therefore this compiler option wouldn't be useful in practice).

What's interesting to note though is that I tried marking pointers __restrict__ in the performance critical sections in 2 of my C++ projects and the assembly generated by Clang was identical in all cases! So while it is true that by default Rust has a theoretical performance advantage (compared to C/C++) because it forbids aliasing pointers I wonder (doubt) whether this will cause Rust binaries to generally run faste…

> so there are lots of array bounds checks in Rust programs

Depends on how those programs were written. Iterators should avoid bounds checking for example.

Re: Rust is now overall faster than C in benchmarks

#440
post #83

Earlier quoted context omitted.

Why bother to write the vtable in the first place? My experience is that C++ that's written for performance will often prefer the use of templates over inheritance since the cost is then paid upfront by the compiler. What's stopping a C programmer from hand-coding template instantiations (via macro or otherwise)?

Sure you are welcome to reimplement C++ in C macros. When your time is worthless anything is possible.

> When your time is worthless anything is possible.

I kinda want this on a mug or something.

Post reply on HN