Live data from Hacker News

Speed of Rust vs. C

kornel.ski

71–80 of 546 posts

Re: Speed of Rust vs. C

#71

Yeah but, C is essentially 32 years old by now. A more useful comparison would be to modern C++.

I think it’s a reasonable comparison. C is still a language that is widely used. In some niches, it is the only acceptable language. Comparing C with Rust is useful for people in those niches. An example of this is the Linux kernel.

Re: Speed of Rust vs. C

#72
post #18

> C libraries typically return opaque pointers to their data structures, to hide implementation details and ensure there's only one copy of each instance of the struct. This costs heap allocations and pointer indirections. Rust's built-in privacy, unique ownership rules, and coding conventions let libraries expose their objects by value The primary reason c libraries do this is not for safety, but to maintain ABI com…

> ABI compatibility Rust provides ABI compatibility against its C ABI, and if you want you can dynamically link against that. What Rust eschews is the insane fragile ABI compatibility of C++, which is a huge pain to deal with as a user: https://community.kde.org/Policies/Binary_Compatibility_Issu... I don't think we'll ever see as comprehensive an ABI out of Rust as we get out of C++, because exposing that much incid…

Yes, and if you use the C abi to dynamically link rust code, you will have exactly the same problem as c: you can't change the layout of your structures without breaking compatibility, unless you use indirecting wrappers.

Re: Speed of Rust vs. C

#73

As an observation, performance optimized code is almost always effectively single-threaded these days, even when using all the cores on a CPU to very efficiently process workloads. Given this, it is not clear to me that Rust actually buys much when it comes to parallel programming for the purposes of performance. Is there another reason to focus on parallelism aside from performance? This reminds me of when I use to…

When we talk about support for threading/concurrent programming in programming languages, it is less about how to reach the theoretical limits of your system best, especially if you are free to architect the whole software stack towards that goal. In that case, your statements might apply.

It is about how easily a programmer, who deals with a certain subtask in a system, can utilize more cores for the this task. Not talking about supercomputing, but looking at a smarktphone or a typical PC. There you usually have most cores just idle unused, but if the user triggers an action, you want to be able to use as many cores as it speeds up computation. Language support for parallelism makes a huge difference there. In Go I can write a function to do a certain computation and quite often it is trivial to spread several calls across goroutines.

Re: Speed of Rust vs. C

#74
post #27
post #18

Earlier quoted context omitted.

> ABI compatibility Rust provides ABI compatibility against its C ABI, and if you want you can dynamically link against that. What Rust eschews is the insane fragile ABI compatibility of C++, which is a huge pain to deal with as a user: https://community.kde.org/Policies/Binary_Compatibility_Issu... I don't think we'll ever see as comprehensive an ABI out of Rust as we get out of C++, because exposing that much incid…

Rust has yet to standardize an ABI. Yes you can call or expose a function with C calling conventions. However, you cant pass all native rust types like this, and lose some semantics. However, as the parent comment you responded to you can enable LTO when compiling C. As rust is mostly always statically linked it basically always got LTO optimizations.

Even with static linking, Rust produces separate compilation units a least at the crate level (and depending on compiler settings, within crates). You won't get LTO between crates if you don't explicitly request it. It does allow inlining across compilation units without LTO, but only for functions explicitly marked as `#[inline]`.

Re: Speed of Rust vs. C

#75

Earlier quoted context omitted.

> As an observation, performance optimized code is almost always effectively single-threaded these days, even when using all the cores on a CPU to very efficiently process workloads. Why? Edit: Thanks for all the replies. It seems this applies to data-parallel workloads only. I'd use a GPU for this. An RTX 3090 has around ~10000 CUDA cores (10000 simultaneous operations) v/s just ~10 for CPUs.

Data locality is everything for computational throughput. Having all data private to a single core is extraordinarily efficient compared to sharing data, and particularly mutable data, across cores. This creates a new problem: how do you balance load across cores? What if the workload is not evenly distributed across the data held by each core? Real workloads are like this! Fortunately, over the last decade, architec…

Can you point to any references/resources summarizing the latest cross-core dynamic load shedding techniques? Are they old techniques just now being applied in practice, or has something new been proposed?

Re: Speed of Rust vs. C

#76
post #8

As an observation, performance optimized code is almost always effectively single-threaded these days, even when using all the cores on a CPU to very efficiently process workloads. Given this, it is not clear to me that Rust actually buys much when it comes to parallel programming for the purposes of performance. Is there another reason to focus on parallelism aside from performance? This reminds me of when I use to…

> As an observation, performance optimized code is almost always effectively single-threaded these days, even when using all the cores on a CPU to very efficiently process workloads. Not my experience at all. One big problem is that most languages in 2021 have very, very poor support for thread-based parallelism. It’s crazy how many languages make it hard to do basic data parallel tasks. That steers people toward wri…

There are a few tasks, where process-based parallelism is working fine. Like a forking server for handling network requests. This is quite efficient and works even if the handling function is not thread save. Obviously, you get memory safety as well.

Unfortunately, that is only a certain subsection of problems and usually you want to be able to use parallel computations on the function call level. There the support for parallel computations of Rust or Go shines. When at each point in the program flow you can decide to go parallel.

Re: Speed of Rust vs. C

#77
post #6
post #4

> "Clever" memory use is frowned upon in Rust. In C, anything goes. For example, in C I'd be tempted to reuse a buffer allocated for one purpose for another purpose later (a technique known as HEARTBLEED). This made me laugh

It's not trivial to write a funny and clever burn, but this just hits the spot...

It's incorrect, however.

Heartbleed wasn't caused by reusing buffers; it was caused by not properly sanitizing the length of the buffer from entrusted input, and reading over it's allocated size, thus allowing the attacker to read into memory that wasn't meant for him.

Re: Speed of Rust vs. C

#78
post #35

Earlier quoted context omitted.

Thanks. What is latency hiding?

There are many operations on data that are relatively slow from a CPU’s perspective — filling a cache line, page faulting, cache coherency, acquiring a lock, waiting on I/O to complete, etc. All of these add latency by stalling execution. In conventional software, when these events occur you simply stall execution, possibly triggering a context switch (which is very expensive). In many types of modern systems, these…

Is there some tool like ps/top /time that I can use measure how much “constructive” work my cpu spend doing?

Re: Speed of Rust vs. C

#79

Earlier quoted context omitted.

It's not a bandwidth issue. Functional programming (especially, say, actor systems) is better for organizing mental models of concurrency when your concurrency is coupled with communication between the components. For hpc, you're typically optimizing for gustafson scaling (versus amdhal scaling) where you are running multiple copies of the same, computationally costly linearly organized code with no coupling between…

FWIW, most supercomputing looks nothing like map-reduce; only the most trivial problems look like that. In a data model sense, a lot of supercomputing is join operation intensive, hence why they spend big bucks on high-bandwidth low-latency interconnects. STREAM benchmarks were more predictive of real-world supercomputing code performance than LAPACK in the majority of case 15+ years ago and it became more biased tow…

I have nothing to add, just wanted to say that reading all your comments this morning has been fascinating and educational. I’ve really enjoyed it so Thanks for sharing. This kind of expert insight is one of the reasons i visit HN.

Re: Speed of Rust vs. C

#80
post #50

Earlier quoted context omitted.

Swift has a stable ABI. It makes different tradeoffs than rust, but I don't think complexity is the cliff. There is a good overview at https://gankra.github.io/blah/swift-abi/

Swift has a stable ABI at the cost of what amounts to runtime reflection, which is expensive. That doesn't really fit with the goals of Rust, I don't think.

This is misleading, especially since Swift binaries do typically ship with actual reflection metadata (unless it is stripped out). The Swift ABI does keep layout information behind a pointer in certain cases, but if you squint at it funny it's basically a vtable but for data. (Actually, even more so than non-fragile ivars are in Objective-C, because I believe actual offsets are not provided, rather you get getter/setter functions…)

I don't disagree that Rust probably would not go this way, but I think that's less "this is spooky reflection" and more "Rust likes static linking and cares less about stable ABIs, plus the general attitude of 'if you're going to make an indirect call the language should make you work for it'".

Post reply on HN