Live data from Hacker News

Speed of Rust vs. C

kornel.ski

61–70 of 546 posts

Re: Speed of Rust vs. C

#61

Earlier quoted context omitted.

Yes, roughly single-threaded async, with each core running a disjoint subset of the workload on data private to that core. You can’t beat the operation throughput. The software architecture challenge is shedding load between cores, since this will hotspot under real workloads with a naive design. Fortunately, smoothly and dynamically shedding load across cores with minimal overhead and latency is a solved design prob…

Ah, I understand now. I misinterpreted "no thread overhead" as meaning "I'm not running things in multiple threads", like the current node.js/javascript obsession, where we just run code in one thread and use a bunch of async to "parallelise". Sorry! I've (badly) written code like you describe -- usually by abusing fork to do my initial data structure setup, then using C pipes to pass jobs around. I suspect there are…

I was also confused. I agree that touching raw threads is usually not the right thing to do, and chains of parallel coroutines are one of the good abstractions. It’s crazy how few languages have easy access to that very basic abstraction.

Re: Speed of Rust vs. C

#62
post #34

Earlier quoted context omitted.

In what way is process based parallelism strictly worse? On Linux a process and a thread in the kernel are both the same thing. The main difference between the two is that threads share memory by default whereas a process would need to explicitly mmap a chunk of memory to share with another process. This means that with threads you get to save RAM because of application code not having to take up more space (except m…

I do not think your model of threads and processes is correct. Processes have different address spaces whereas threads share an address space. Context switching between threads is much cheaper than context switching between processes because you do not have to swap page tables and do a tlb flush. tlb flushes are extremely expensive. I also think you are misunderstanding how mmap works. mmap is not related to thread s…

Not the parent, but... mmap is related to thread spawning (well, process forking) in that using the MAP_SHARED flag will result in a pointer that is valid shared memory for both the parent process and any forked processes.

Re: Speed of Rust vs. C

#63
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.

Do you have a source on this? I didn't think Swift requires runtime reflection to make calling across module boundaries work - I thought `.swiftmodule` files are essentially IR code to avoid this

Re: Speed of Rust vs. C

#64
post #34

Earlier quoted context omitted.

In what way is process based parallelism strictly worse? On Linux a process and a thread in the kernel are both the same thing. The main difference between the two is that threads share memory by default whereas a process would need to explicitly mmap a chunk of memory to share with another process. This means that with threads you get to save RAM because of application code not having to take up more space (except m…

I do not think your model of threads and processes is correct. Processes have different address spaces whereas threads share an address space. Context switching between threads is much cheaper than context switching between processes because you do not have to swap page tables and do a tlb flush. tlb flushes are extremely expensive. I also think you are misunderstanding how mmap works. mmap is not related to thread s…

If you stick to one process per core, the number of TLB flushes doesn't change. You can set processor affinity to make sure of that. If you create more threads/processes than cores, you might be able to get measurable impact.

I don't understand your comment about mmap. It is often used to share memory between related processes.

Re: Speed of Rust vs. C

#65

A graph would be good. Any graph. Preferably multiple. Otherwise, this is all empirical data. Show me why Rust wins, and how. Telling me "doubly-linked lists are slow" is not useful, as a developer considering one of these two languages.

This isn't that type of post. Sometimes what's useful is a brain-dump of heuristics and tidbits and general impressions formed over years and years of experience. Sometimes that's more useful, or even more accurate, than hard benchmark data.

Re: Speed of Rust vs. C

#66
> computed goto

I did a deep dive into this topic lately when exploring whether to add a language feature to zig for this purpose. I found that, although finnicky, LLVM is able to generate the desired machine code if you give it a simple enough while loop continue expression[1]. So I think it's reasonable to not have a computed goto language feature.

More details here, with lots of fun godbolt links: https://github.com/ziglang/zig/issues/8220

[1]: https://godbolt.org/z/T3v881

Re: Speed of Rust vs. C

#67

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…

My impression is that what kind of parallelism patterns you need is pretty consistent within entire fields of programming. So you can go an entire career of performance optimization within HPC, game dev, film rendering or trading systems and never use the patterns the others say they use all the time. My experience with process-based parallelism is that yes on Linux it's basically isomorphic to thread-based paralleli…

When you have built in support for threads in a language, it definitely makes sense that it would be easier to use than operating system mechanisms. For a lot of the non-embedded code that I end up writing, though, there's usually an inherent benefit to using processes over threads. It usually comes down to the benefits of having separate memory spaces. You can safely use code that was never written to be thread-safe, saving time otherwise spent refactoring gnarly old code. Also, it makes it a lot easier to mix and match different languages. For python in particular, it avoids having to battle for the global interpreter lock.

I think what's nice about rust is that, because it makes it difficult to write thread-unsafe code, it's naturally easier to add threading at some point in the future without too much pain. As a result, more applications can benefit from having access to multiple CPU cores. I don't think that's quite the same thing as pure performance per watt, though. That really comes down to how the code was written, and how well the compiler can optimize it. Rust may have some advantages there over C, since it constrains what you can do so much that the compiler has a smaller state space to optimize over. Someone who knows what they're doing in C, though, could likely write very efficient code that effectively uses parallelism, and may gain an edge over rust simply by cleverly leveraging the relative lack of training wheels. For high performance compute, rust vs. C may be a wash. For consumer facing applications, though, the more programs that can use multiple cores to run faster (even if less efficiently), the better.

Re: Speed of Rust vs. C

#68
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

This was actually a somewhat significant reason I shared this article. (^.^)

Re: Speed of Rust vs. C

#69
post #63
post #50

Earlier quoted context omitted.

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.

Do you have a source on this? I didn't think Swift requires runtime reflection to make calling across module boundaries work - I thought `.swiftmodule` files are essentially IR code to avoid this

Pretty sure the link the parent (to my comment) provided explains this.

It's not the same kind of runtime reflection people talk about when they (for example) use reflection in Java. It's hidden from the library-using programmer, but the calling needs to "communicate" with the library to figure out data layouts and such, and that sounds a lot like reflection to me.

Re: Speed of Rust vs. C

#70
post #57

I appreciate the article, but it would be really nice if the author could add a timestamp to his blog posts. Without timestamps, it's impossible to know if any issue described in the article body still exists. I didn't read it, because it might present outdated knowledge.

I read it. Didn’t find any outdated information in it.
Post reply on HN