If Rust implementation is father than C's, kudos goes to the compiler, not to the language
Rust is now overall faster than C in benchmarks
141–150 of 445 posts
Re: Rust is now overall faster than C in benchmarks
#142Looking at the reverse-complement code, it appears that the Rust and C implementations are using different algorithms: https://benchmarksgame-team.pages.debian.net/benchmarksgame/... https://benchmarksgame-team.pages.debian.net/benchmarksgame/... On a quick inspection: - The Rust code is about twice as long. - The Rust code has CPU feature detection and SSE intrinsics, while the C code is more idiomatic. - The lookup…
I recall an anecdote about how Haskell actually outperformed C on various tree benchmarks because it was using a better implementation. At some point, the C programmers got fed up with the airs of superiority from Haskell programmers, ported the Haskell implementation, and reclaimed their position. I wouldn't be surprised if there's something similar happening here.
In this case it seems like benchmark code is allowed to use intrinsics, which can degenerate into a situation where a benchmark in language X is more "glorified x86 Assembly code" than actual code in language X.
This is not very useful for comparing languages IMO. Especially since all of Rust, C, C++ can use this strategy and become almost identical in both code and performance.
Re: Rust is now overall faster than C in benchmarks
#143Earlier quoted context omitted.
> C compilers have to assume that pointers to memory locations can overlap, unless you mark them __restrict... What I don't fully understand is: "GCC has the option -fstrict-aliasing which enables aliasing optimizations globally and expects you to ensure that nothing gets illegally aliased. This optimization is enabled for -O2 and -O3 I believe." (source: https://stackoverflow.com/a/7298596 ) Doesn't this mean that C…
restrict and strict aliasing have to do with the same general concept, but aren't the same. They both have to do with allowing the compiler to optimize around assuming that writes to one pointer won't be visible while reading from another. As a concrete example, can the following branches be merged? void foo(/*restrict*/ bool* x, int* y) { if (*x) { printf("foo\n"); *y = 0; } if (*x) { printf("bar\n"); } } Enabling s…
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).
Re: Rust is now overall faster than C in benchmarks
#144Earlier quoted context omitted.
Also lack of generics can make it slow, e.g. qsort() requires a function call for each comparison. So C++'s std::sort() can be significantly faster on an array of integers.
It's more to do with the fact that std::sort's definition is visible to the compiler and qsort() is not. Put qsort() code in stdlib.h, make it static and write a static intcmp() and you'll see the compiler inline that no problem.
Re: Rust is now overall faster than C in benchmarks
#145Earlier quoted context omitted.
I benchmarked it several times in the past and couldn't replicate std::sort being faster (GCC with high optimization settings). Anyway both are slow. If you need fast sort you need an implementation without any function calls (no recursive calls) and both the pivot choice and the chunk size at which insert sort kicks in optimized to your data and hardware. My experience is that you can beat built in sort by 2x to 3x.
How would you perform this optimization? If it’s the same data getting sorted, why not put it in an ordered data structure?
One library I have exploits the fact that D templates are embarrassingly better than C++'s, so you can actually benchmark a template against it's parameters in a clean manner without overhead - that could be anything from a size_t parameter for a sort or a datastructure for example.
enum cpuidRange = iota(1, 10).map!(ctfeRepeater).array;
@TemplateBenchmark!(0, cpuidRange)
@FunctionBenchmark!("Measure", iota(1, 10), (_) => [1, 2, 3, 4])(meas)
static int sum(string asmLine)(inout int[] input)
{
int tmp;
foreach (i; input)
{
tmp += i;
mixin("asm { ", asmLine, ";}");
}
return tmp;
}
This made-up (pointless) benchmark measures how insert a number of cpuid instructions into the loop of a summing function affects it's runtime. My library writes the code from your specification as above to generate the instantiations and loop to measure the performance. As you might guess, the answer is a lot (CPUID is slow and serializing).edit: https://github.com/maxhaton/chimpfella - I haven't bothered to add pmc support yet
Re: Rust is now overall faster than C in benchmarks
#146Re: Rust is now overall faster than C in benchmarks
#147Looking at the reverse-complement code, it appears that the Rust and C implementations are using different algorithms: https://benchmarksgame-team.pages.debian.net/benchmarksgame/... https://benchmarksgame-team.pages.debian.net/benchmarksgame/... On a quick inspection: - The Rust code is about twice as long. - The Rust code has CPU feature detection and SSE intrinsics, while the C code is more idiomatic. - The lookup…
What does "idiomatic" C even mean? It's a high level assembler and as such should not limit the creativity of programmers using it. C code that pretends it does not need to care about it's platform is not idiomatic, it's just suboptimal.
- Code that most C books/courses would teach you how to write
- Portable C code (arguably portability is one of C's biggest successes!)
- Code that you'd expect to find in the K&R book
Re: Rust is now overall faster than C in benchmarks
#148Earlier quoted context omitted.
It's more to do with the fact that std::sort's definition is visible to the compiler and qsort() is not. Put qsort() code in stdlib.h, make it static and write a static intcmp() and you'll see the compiler inline that no problem.
Sure you can hard-code intcmp into qsort but then it would only work for arrays of ints. You could do some macro magic instead of templates e.g. `DEFINE_QSORT(int, intcmp)` which could stamp out `qsort_int` but that's not a part of the stdlib. C++ arguably gets this right since sort and sort will be separate functions, although templates are of course a footgun. And of course duping the logic for std::sort for a bunc…
When this is done, the compiler can inline qsort, and replace the indirect function call with an inlined version of intcmp, and then things are equivalent.
Re: Rust is now overall faster than C in benchmarks
#149Apart from those benchmark games a lot of real world C is a lot less performant than people think it might be. I spent a fair amount of time reviewing C code in the last 5 years - and things that pop up in nearly every review are costly string operations. Linear counts due to the use of null terminated strings and extra allocations for substrings to attach null terminators, or just deep copies because ownership can’t…
In many programs in many domains the sizes of these data structures will rarely exceed this limit.
Re: Rust is now overall faster than C in benchmarks
#150Apart from those benchmark games a lot of real world C is a lot less performant than people think it might be. I spent a fair amount of time reviewing C code in the last 5 years - and things that pop up in nearly every review are costly string operations. Linear counts due to the use of null terminated strings and extra allocations for substrings to attach null terminators, or just deep copies because ownership can’t…
Doesn't that mean that null terminated strings is idiomatic C? That is, my understanding of the term idiomatic is that it is defined by whatever is most natural to users of a language regardless of whether it is the most performant.