Live data from Hacker News

Speed of Rust vs. C

kornel.ski

411–420 of 546 posts

Re: Speed of Rust vs. C

#411
post #344
post #340

Earlier quoted context omitted.

Bulk operations are not really about layout, they are about whether you mentally consider each little data structure to be an individual entity with its own lifetime, or not, because this determines what the code looks like, which determines how fast it is. (Though layout does help with regard to cache hits and so forth).

"mentally"? I don't know what you're trying to imply that Rust does, but I'll reiterate that Rust lifetimes don't exist at code generation time. They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine). If you create `Vec ` in Rust, then all objects will be allocated and laid out toget…

> They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine).

This kind of reasoning seems like it makes sense, but actually it is false. ("Modern C++" people make the same arguments when arguing that you should use "zero-cost abstractions" all over the place). Abstractions determine how people write code, and the way they write the code determines the performance of the code.

When you conceptualize a bunch of stuff as different objects with different lifetimes, you are going to write code treating stuff as different objects with different lifetimes. That is slow.

> If you create `Vec` in Rust, then all objects will be allocated and laid out together as one contiguous chunk of memory

Sure, and that covers a small percentage of the use cases I am talking about, but not most of them.

Re: Speed of Rust vs. C

#412

Its just amusing, in this thread everyone with critical thinking and skeptical is down voted, even if one expresses himself moderately. It shows how much of zealots, Rust fanboys have become.

I think it would a be very in interesting psychological study on the reason for this. The similar thing happens for some other languages, but never at the level of rust.

Re: Speed of Rust vs. C

#413
post #408

Earlier quoted context omitted.

> You chose an embarrassingly parallel problem Well, I mean, you chose an embarrassingly general statement to make? Play stupid games, win stupid prizes. > which most programs are not Programs? Or problems? Who says? It's not at all obvious to me that it's true. And even if it were true, "embarrassingly parallel" problems are nowhere close to uncommon. > When you try to parallelize a structurally complicated algorith…

If you do not understand that "embarrassingly parallel" is a technical term and that it's generally understood that most programs are not easily parallelizable, there is not a discussion we can have here.

Really feels like you're just digging yourself deeper into a hole here:

Burntsushi began with "here, parallelization is beating out memory locality and optimization in its impact," but explicitly declined to generalize this the way you generalized your claim about memory.

He further pointed out that ripgrep is fast not just because of parallelization, but also because of how it handles memory.

Then you come back with "you can't always parallelize this well" (which burntsushi agreed with from the beginning) and "you also need to deal with memory" (which ripgrep does)? How is this burntsushi's problem with understanding "embarrassingly parallel" and not your problem with understanding Rust?

Re: Speed of Rust vs. C

#414
post #408

Earlier quoted context omitted.

> You chose an embarrassingly parallel problem Well, I mean, you chose an embarrassingly general statement to make? Play stupid games, win stupid prizes. > which most programs are not Programs? Or problems? Who says? It's not at all obvious to me that it's true. And even if it were true, "embarrassingly parallel" problems are nowhere close to uncommon. > When you try to parallelize a structurally complicated algorith…

If you do not understand that "embarrassingly parallel" is a technical term and that it's generally understood that most programs are not easily parallelizable, there is not a discussion we can have here.

I agree that a discussion is difficult. Your comments are so vague and generalized that it's not clear what you're talking about at all. Bring something more specific to the table like the OP did instead of pontificating on generalities.

Re: Speed of Rust vs. C

#415
post #411
post #344

Earlier quoted context omitted.

"mentally"? I don't know what you're trying to imply that Rust does, but I'll reiterate that Rust lifetimes don't exist at code generation time. They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine). If you create `Vec ` in Rust, then all objects will be allocated and laid out toget…

> They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine). This kind of reasoning seems like it makes sense, but actually it is false. ("Modern C++" people make the same arguments when arguing that you should use "zero-cost abstractions" all over the place). Abstractions determine how…

> When you conceptualize a bunch of stuff as different objects with different lifetimes, you are going to write code treating stuff as different objects with different lifetimes. That is slow.

This is not how lifetimes work at all. In fact this sounds like the sort of thing someone who has never read or written anything using lifetimes would say: even the most basic applications of lifetimes go beyond this.

Fundamentally, any particular lifetime variable (the 'a syntax) erases the distinctions between individual objects. Rust doesn't even have syntax for the lifetime of any individual object. Research in this area tends to use the term "region" rather than "lifetime" for this reason.

Lifetimes actually fit in quite nicely with the sorts of things programs do to optimize memory locality and allocations.

> Sure, and that covers a small percentage of the use cases I am talking about, but not most of them.

Fortunately the other stuff you are talking about works just fine in Rust as well.

Re: Speed of Rust vs. C

#416
post #335

Earlier quoted context omitted.

Sure, but you are still going to be constrained greatly in terms of what those allocators are able to do, are you not?

In what way? What kind of constraints are you imagining here?

I guess I am confused by the question. The job of the borrow checker is to constrain what you are allowed to do, and it's well-understood that it constrains you to a subset of correct programs, so that you stay in a realm that is analyzable.

Re: Speed of Rust vs. C

#417
post #415
post #411

Earlier quoted context omitted.

> They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine). This kind of reasoning seems like it makes sense, but actually it is false. ("Modern C++" people make the same arguments when arguing that you should use "zero-cost abstractions" all over the place). Abstractions determine how…

> When you conceptualize a bunch of stuff as different objects with different lifetimes, you are going to write code treating stuff as different objects with different lifetimes. That is slow. This is not how lifetimes work at all. In fact this sounds like the sort of thing someone who has never read or written anything using lifetimes would say: even the most basic applications of lifetimes go beyond this. Fundament…

I am talking about RAII. RAII leads to programs that are inherently slow.

Re: Speed of Rust vs. C

#418
post #104

To practise Rust, I rewrote my small C99 library in it [1]. Performance is more or less the same, I only had to use unchecked array access in one small hot loop (details in README.md). I haven't ported multithreading yet, but I expect Rust's Rayon parallel iterators will likewise be comparable to OpenMP. [1] https://github.com/GreatAttractor/libskry_r

Your C library does not check malloc returns and also malloc and free everywhere inside library functions are not the best way to write a C library.

As for malloc/free, I'm guessing the recommendation is to allow the user to pass their own allocator on library initialization?

Non-checked malloc returns - ouch, I count 12 (out of 56) without a check. Thanks for pointing this out.

Re: Speed of Rust vs. C

#419
post #411
post #344

Earlier quoted context omitted.

"mentally"? I don't know what you're trying to imply that Rust does, but I'll reiterate that Rust lifetimes don't exist at code generation time. They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine). If you create `Vec ` in Rust, then all objects will be allocated and laid out toget…

> They're not a runtime construct, they have zero influence over what code does at run time (e.g. mrustc compiler doesn't implement lifetimes, but bootstraps the whole Rust compiler just fine). This kind of reasoning seems like it makes sense, but actually it is false. ("Modern C++" people make the same arguments when arguing that you should use "zero-cost abstractions" all over the place). Abstractions determine how…

You haven't really explained in any detail what is slow about "treating stuff as objects with different lifetimes", and specifically how Rust differs there from C. Can you give an example?

Maybe you'd be interested to hear that Rust's borrow checker is very friendly to the ECS pattern, and works with ECS much better than with the classic OOP "Player extends Entity" approach.

Re: Speed of Rust vs. C

#420
post #416

Earlier quoted context omitted.

In what way? What kind of constraints are you imagining here?

I guess I am confused by the question. The job of the borrow checker is to constrain what you are allowed to do, and it's well-understood that it constrains you to a subset of correct programs, so that you stay in a realm that is analyzable.

Sure, but the borrow checker only operates on references. Rust gives you the tools to work with raw everything, if you dip into unsafe. Memory allocators, doing this kind of low-level thing, don't work with references. Let's say you want to implement a global allocator (this is the only current API in stable Rust, non-global allocators are on the way). The trait you use, which gives you the equivalent of malloc/free, has this signature:

  unsafe impl GlobalAlloc {
      pub unsafe fn alloc(&self, layout: Layout) -> *mut u8;
      pub unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
  }
Note the *mut u8 rather than say, &mut u8. Most people would not be using this interface directly, they'd be using a data structure that uses it internally.

Now, there's a good argument to be had about safe and unsafe, how much you need, in what proportion, and in what kinds of programs... but when you say things like "C allows you to do bulk memory operations, Rust does not" and ask about the borrow checker when talking about allocators, to someone who is familiar with Rust's details, it seems like you are misinformed somehow, which makes it really hard to engage constructively with what you're saying.

Post reply on HN