4 ms·
I don't even know what you are trying to say here. C++ is great to program in and has a fantastic eco system of tools and libraries. It is something you can saf
by CyberDildonics 3y ago
I don't even know what you are trying to say here. C++ is great to program in and has a fantastic eco system of tools and libraries. It is something you can safely base a business around.
You won't get "extreme performance" from C++ because it is buried under the weight of decades of compatibility hacks.
This doesn't even make sense. What is an example of something that can't be fast because it is done in C++? What "compatibility hacks" are slowing programs down?
This does not sound like something someone with experience in C++ would say.
- tialaramex 3y ago> This doesn't even make sense. What is an example of something that can't be fast because it is done in C++? What "compatibility hacks" are slowing programs down? Let's look at two very different perf leaks in ISO C++. Firstly move assignment which is right at the heart of the language. Initially C++ doesn't have move semantics at all, which is a problem because in a bunch of cases that's key to "extreme performance". So in the "lost decade" period between C++ 03 and C++ 11 considerable work was done to figure out a way to unlock this, but of course C++ insisted on backwards compatibility with the code written for C++ 98 with no such semantic. The result is that the actual move semantic people wanted can't quite be done, this is now called "destructive move" and proponents of the compatible option C++ 11 and later had claim it's equivalent to the move they delivered, plus delete. But that's... disingenuous. The C++ 11 move is actually (move + create), so to build "destructive move", when that's what you need, you must write (move + create) + destroy. Sometimes the compiler can see what's happening here and emit the same machine code you'd get in a language with native move semantics, but sometimes it has no way to figure this out, and you're emitting move + create + destroy, which is markedly slower as well as of course being more error prone. Secondly right up at the surface, where we can feel the rain, and appropriately something Bjarne Stroustrup (author of the book we're talking about here) has noticed himself, the provided growable array, std::vector lacks the bifurcated reservation. Vec::reserve_exact isn't enough, you need Vec::reserve as well for good performance with a growable array API, but C++ doesn't provide this, it provides only Vec::reserve_exact under the name "reserve" and there's no room to offer both in the compatible API, which means as a user/ application programmer this fundamental type is a small perf leak. Bjarne shrugs this off, oh well, just don't use the reserve API to get performance benefits. But everybody else can do so, this choice means C++ is leaving it on the table for somebody else with a better growable array type. Finally though, I want to look at a beacon over the horizon, where "extreme performance" really is something they're thinking about. Iterator Loops (sometimes "Chunk Loops") are a technique where the language lets you directly express in your definition of a loop how it can be performed in a SIMD-fashion, so e.g. you write the code to search an N byte buffer for the byte you're looking for, but then revisit that loop and also write code for searching N=M*16 bytes, using 16 bytes at once. This lets you write, in a high level language, code which will be easy for a compiler to SIMD accelerate without fragile idiom recognition. C++ of course does not provide Iterator Loops and instead you'd reach for manual inline assembler in these cases today.
- CyberDildonics 3y agoWho is filling your head with all this? I have never seen any program slow down over a move, because you should be moving enough data that copying a pointer doesn't matter anyway. This is trivial stuff. Show me in an actual program somewhere that shows what you're talking about. Vec::reserve_exact isn't enough, you need Vec::reserve Reserve reserves the amount that you give it. This isn't hard or complicated. What exactly do you think it should do differently, and how hard would it be to write your own? Vector is a simple data structure. Anything you don't like about it isn't a language limitation. this fundamental type is a small perf leak Show me a program that illustrates what you are talking about. I want to look at a beacon over the horizon, You can do this with intrinsics or libraries that use intrinsics. the language lets you directly express in your definition of a loop This isn't a performance limitation it's a convenience you want integrated into the language. There is one that does this, it's called ISPC. Is that what you use? This seems to me like you've gone down some sort of anti C++ rabbit hole where people who don't know what they're doing get worked up about things that don't matter. Meanwhile in the standard library there is actually the unordered_map design which is stifled by algorithmic complexity requirements, but people use flat maps to get around that.
- tialaramex 3y ago> I have never seen any program slow down over a move I'm sure, and yet the people who care have noticed that C++ is slower, that's what P1144 and P2786 and so on are trying to solve, without quite saying "destructive move" out loud. Here's the current iteration of P1144: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1144r10.html https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p11... Like pointer provenance this is something WG21 would prefer not to think about because it's embarrassing, so it has hung around like a bad smell for quite a few years but I suspect (unlike provenance work) it'll get into C++ 26 in some form. > Reserve reserves the amount that you give it. This isn't hard or complicated. What exactly do you think it should do differently It's OK, after all Bjarne Stroustrup didn't see this either, but you've missed something quite important The whole idea of this type is amortized constant time growth, typically via doubling although any fixed ratio would work and there could be a benefit to choosing other ratios in principle (Folly has a long paper about this). For this purpose it's crucial that capacity doesn't grow linearly. But if our only reservation mechanism is Vec::reserve_exact (aka C++ reserve) we end up with linear growth. Bjarne's solution is to abandon use of reserve for performance, but we can do much better by just bifurcating the API as Rust did (and as some other languages do) I started writing a program to illustrate this, but it's probably easier to just spell it out with an example. Suppose we receive Doodads over the network, they arrive in groups of say up to 20 Doodads at a time, and we don't know in advance how many there will be, until the last group indicates it's the end of the Doodads. Typically in total there's maybe 40-50 Doodads, but there can be as few as five (one group of just five) or as many as a thousand. We're going to put all the Doodads in a growable array as we receive them. Let's walk through receiving 19, 14, 18, 12 and finally 6 Doodads. Bjarne says don't bother with reservation as in C++ this doesn't work for performance, so we just use the "natural" doubling. Our std::vector allocates space for 1, 2, 4, 8, 16, 32, 64 and finally 128 Doodads (eight allocations), and does a total of 127 copy Doodad operations. Surely we can do better knowing what's coming? If we ignore Bjarne's advice and use C++ std::vector reserve to reserve for each group, we allocate space for 19, 33, 51, 63 and finally 69 Doodads (five allocations), and we perform 19 + 33 + 51 + 63 = 166 copy operations. Fewer allocations, more copies. If we have the bifurcated API, we allocate space for 19, 38 and 76 Doodads (three allocations) and we do 19 + 33 = 52 copy operations. Significantly better. > This isn't a performance limitation it's a convenience you want integrated into the language I disagree and the results speak for themselves. > There is one that does this, it's called ISPC. Is that what you use? I've never used ISPC. It's somewhat interesting although since it's Intel focused of course it's not actually portable. > This seems to me like you've gone down some sort of anti C++ rabbit hole where people who don't know what they're doing get worked up about things that don't matter. It's always funniest to read about what "doesn't matter" right before it gets fixed and suddenly it's important. The growable array API probably won't get fixed, education means that Bjarne's "Don't use reserve" taints a whole population so even if you fix this today it'd be years before the C++ programming community use reserve where it's appropriate but I expect "relocation" in some form will land, and chances are in a few years you'll be telling people it's why C++ has "extreme performance"...