Live data from Hacker News

The Sad State of Debug Performance in C++

vittorioromeo.info

81–90 of 111 posts

Re: The Sad State of Debug Performance in C++

#81
post #44
post #35

I ran into these problems with std::unordered_map. While developing my game, I would always run it in debug mode because I need to debug it. Loading a game world was taking around 12 seconds, and it was beginning to grate on me because of the increased iteration times. So I decided to profile it and see what was taking so long. I compiled in release mode to begin debugging, and it magically took the world load time d…

It'd maybe be nice to be able to mark which code gets optimized. If I could make all std as "don't debug this and keep it optimized" I would. I know some debuggers have the option to at least not step into certain code that that doesn't solve the optimization issue

You don't have to compile every file with the same flags. You can vary them with each invocation of the compiler, so trivially get what you want at the translation unit level.

Re: The Sad State of Debug Performance in C++

#82

Earlier quoted context omitted.

> Presumably my code has been less than optimally efficient or something Yep, it was either less efficient than it could be, or more clunky, or incorrect. I remember back when boost was still a thing, everyone using boost::shared_ptr indiscriminately. Refcounting has a very nontrivial cost to it if implemented correctly. Things like rvalue refs and std::move allow to properly implement the concept of "ownership trans…

I've been using boost::shared_ptr for 22+ years. My code has no concept of ownership transfer, ever. The reason for shared_ptr in our codebase is not to move ownership around, but to ensure correct lifetimes. For examples, objects in the model cannot die until the view has dropped references to them.

> to ensure correct lifetimes

Refcounted pointers don't make that guarantee. They just guarantee that if they are incorrect they will not deallocate (== will leave garbage) and thus never result in a use-after-deletion.

Most of the time they are fine but they can't handle circular structures. This is why C++ has the weak_ptr.

Re: The Sad State of Debug Performance in C++

#83

Earlier quoted context omitted.

I've been using boost::shared_ptr for 22+ years. My code has no concept of ownership transfer, ever. The reason for shared_ptr in our codebase is not to move ownership around, but to ensure correct lifetimes. For examples, objects in the model cannot die until the view has dropped references to them.

Yup, that's bad. Unless you actually have a complicated ownership scheme or shared state across multiple threads, unique ownership is preferable on all accounts. At the point where 1) your object graph is complex enough to warrant the ubiquitous use of shared pointers; 2) you can afford the performance hit it's better to use an actual garbage collector, even if it's bolted-on unreal engine-style. With shared_ptr-styl…

Our object graph is for a DAW, one of the most complex applications floating around. Multiple threads, some with RT constraints, multiple UIs acting as both view and controller. No GC acceptable here.

Re: The Sad State of Debug Performance in C++

#84
post #82

Earlier quoted context omitted.

I've been using boost::shared_ptr for 22+ years. My code has no concept of ownership transfer, ever. The reason for shared_ptr in our codebase is not to move ownership around, but to ensure correct lifetimes. For examples, objects in the model cannot die until the view has dropped references to them.

> to ensure correct lifetimes Refcounted pointers don't make that guarantee. They just guarantee that if they are incorrect they will not deallocate (== will leave garbage) and thus never result in a use-after-deletion. Most of the time they are fine but they can't handle circular structures. This is why C++ has the weak_ptr.

No use-after-deletion is precisely what is required. And yes, we use weak_ptr too, for some things.

The alternative is "no language-level references, any time you want object "Foo", go look it up in some table". We opted not to do that.

Re: The Sad State of Debug Performance in C++

#85

Earlier quoted context omitted.

Yup, that's bad. Unless you actually have a complicated ownership scheme or shared state across multiple threads, unique ownership is preferable on all accounts. At the point where 1) your object graph is complex enough to warrant the ubiquitous use of shared pointers; 2) you can afford the performance hit it's better to use an actual garbage collector, even if it's bolted-on unreal engine-style. With shared_ptr-styl…

Our object graph is for a DAW, one of the most complex applications floating around. Multiple threads, some with RT constraints, multiple UIs acting as both view and controller. No GC acceptable here.

as long as you can control when GC runs, it can be acceptable for applications with soft-realtime constraints (not all GC languages give you that level of flexibility though). at least I would prefer that situation over being faced with cascading destruction of refcounted objective-c objects at the most inconvenient moment, with no other recourse than complete rearchitecting.

Re: The Sad State of Debug Performance in C++

#86

Earlier quoted context omitted.

Yup, that's bad. Unless you actually have a complicated ownership scheme or shared state across multiple threads, unique ownership is preferable on all accounts. At the point where 1) your object graph is complex enough to warrant the ubiquitous use of shared pointers; 2) you can afford the performance hit it's better to use an actual garbage collector, even if it's bolted-on unreal engine-style. With shared_ptr-styl…

>It's actually less predictable than a GC that you can run manually at fixed intervals or whenever a convenient opportunity arises. Not really. It's difficult to reason about, but it's entirely deterministic, unlike a tracing GC.

when you cross a certain level of complexity, the deterministic nature becomes a Turing tarpit of sorts: yes, it's "deterministic", but the number of factors affecting the behavior is so large and their interactions so complex that it might as well be "non-deterministic" -- it's impractical to reason about in detail.

Re: The Sad State of Debug Performance in C++

#87

I've been using C++ since 1993. I still don't understand how I've written all this code and never once found myself using, or wishing I could use std::move. Presumably my code has been less than optimally efficient or something, because it seems that most people talking about "modern" C++ view it as absolutely central to the language.

> I've been using C++ since 1993. I still don't understand how I've written all this code and never once found myself using, or wishing I could use std::move. No offense, but are you using modern C++? One of the most common uses of std::move is around ownership transfer of std::unique_ptr - most moderately big projects will have those. Other uses are around preventing copies, etc but those need more thought since you…

Well, "modern" is relative. We just recently moved to C++11 :)

We do not use unique_ptr and to be honest I can find little to no use for it anywhere in our 600k lines of C++.

Re: The Sad State of Debug Performance in C++

#88

Earlier quoted context omitted.

Our object graph is for a DAW, one of the most complex applications floating around. Multiple threads, some with RT constraints, multiple UIs acting as both view and controller. No GC acceptable here.

as long as you can control when GC runs, it can be acceptable for applications with soft-realtime constraints (not all GC languages give you that level of flexibility though). at least I would prefer that situation over being faced with cascading destruction of refcounted objective-c objects at the most inconvenient moment, with no other recourse than complete rearchitecting.

the GC doesn't solve the problem of no-use-after-destruction, only the timing (and potentially thread) of destructor calling. you still need a refcnt'ing mechanism to make sure that nothing can be considered for GC before nobody is holding a reference to it anymore.

Re: The Sad State of Debug Performance in C++

#89
post #19

I'm with Kernigham and Pike: the debugger is for getting a stack trace out of core dumps. Printf is for debugging.

oh where is that quote? that's great!

In the 'practice of programming'. https://www.cs.princeton.edu/~bwk/tpop.webpage/ I last read it some years ago so I can't tell you exactly what they said. I do know that when pointed out I realized I suffer from the same sins they hate about debuggers: I would step through code mindlessly, changing variables and the like, but never stopping to think. While printf is more painful it forces me to think why is the code in that state, which is key to fixing bugs.

Re: The Sad State of Debug Performance in C++

#90

I've been using C++ since 1993. I still don't understand how I've written all this code and never once found myself using, or wishing I could use std::move. Presumably my code has been less than optimally efficient or something, because it seems that most people talking about "modern" C++ view it as absolutely central to the language.

Well Said.

IMO, a large set of "Modern C++" fanboys have a serious case of "Featuritis"; Merely a focus on the trivial use without understanding the motivation behind it and its place in the larger scheme of building systems. It is like they believe more knowledge of keywords/buzzwords == more expertise.

Even Scott Meyers said this: https://news.ycombinator.com/item?id=27945383

Post reply on HN