Performance difference



  • Is there a performance/ram usage difference?

    class Foo {
    const QString& string = "string";
    };
    
    Foo bar;
    function.setStringValue(bar.string)
    
    class Foo {
    const QString& string = "string";
    };
    
    Foo bar;
    const myLocalString = bar.string;
    function.setStringValue(myLocalString)
    

    I imagine that myLocalString does take something even if almost nothing?
    Do recent compilers optimize this?



  • @damianatorrpm
    You'll never know for sure which compiler will do what optimization with which compilation flags. Nor are you supposed to worry your little head over it, and certainly not for this :)

    I'm trying to get my head round this. Since your string member variable declaration is QString&, I could be wrong(!) but I don't think your const myLocalString = bar.string takes any space at all (or generates any code)!? There is no need for compiler to actually have any variable/storage for a reference, I think here myLocalString is effectively an "alias" for Foo's const QString& string. [Correct me, you can't reassign myLocalString after this, can you? You certainly can't e.g. increment it, but I don't think you're even allowed to reassign a reference "variable" like this after initialization, are you? And I don't think you can take the address, auto zzz = &myLocalString, either, which tells you something about it [not] being a variable, though I might be mistaken on this bit?] I don't do C++ so I can't check :)


  • Moderators

    @damianatorrpm Well, first of all const myLocalString = bar.string; is not a valid code. You're missing a type.

    If you change it to const QString myLocalString = bar.string; then it's unlikely that it gets completely optimized away as the constructor has side effects and compiler can't just skip that. QString is an implicitly shared type, so the cost is amortized somewhat, but it is still something.
    On the other hand if you do const QString& myLocalString = bar.string; a reference is just a syntax for a pointer, and, since it's a local variable, it's almost certainly just an address placed in CPU's register and not a separate variable in memory (at least when compiler optimizations are enabled, i.e. it's not a debug build).

    Keep in mind that in some rare cases it can actually be better to make that copy to local variable. It is usually when you access some global variable in another module often enough for it to matter but not often enough for it to stay in cache. Having a stack based local variable can be better at those times, but that is a kind of decision you make after profiling and confirming the case, not something you do as a habit or on a hunch.

    More times than not though a local const& like that will get optimized away, so this should be your default, which you adjust to something else only if you have credible reasons to suspect it's a problem.
    In your case, since Foo is local too, it will likely get optimized away entirely leaving only the string inside.

    Here's a little example, changed to avoid that Foo removal for illustration purposes. Take a look at the assembly output: https://godbolt.org/z/9Uqrqg. You don't have to know the syntax but you can see the output is short and exactly the same for versions with and without the const& variable, but it can't optimize away a non & copy.



  • @Chris-Kawa said in Performance difference:

    Keep in mind that in some rare cases it can actually be better to make that copy to local variable. It is usually when you access some global variable in another module often enough for it to matter but not often enough for it to stay in cache. Having a stack based local variable can be better at those times, but that is a kind of decision you make after profiling and confirming the case, not something you do as a habit or on a hunch.
    More times than not though a local const& like that will get optimized away, so this should be your default, which you adjust to something else only if you have credible reasons to suspect it's a problem.

    Thanks a lot!



  • @Chris-Kawa said in Performance difference:

    Here's a little example, changed to avoid that Foo removal for illustration purposes. Take a look at the assembly output: https://godbolt.org/z/9Uqrqg. You don't have to know the syntax but you can see the output is short and exactly the same for versions with and without the const& variable [...]

    Very interesting! I had a play there, trying various compilers & optimization levels. Basically they all generated different code for func1 (no variable) vs func2 (variable) if you do not specify an optimization flag (-O...). Any optimization level had gcc/clang etc. make them identical, for msvc not the default optimization level, I had to up a bit to get the code to become the same.


  • Moderators

    @JonB The default optimization level for MSVC in Release build is /O2 and it gives me the same result for func1 and func2: https://godbolt.org/z/rjL--B. Are you sure you checked it right?



  • @Chris-Kawa
    Yes, because I wasn't comparing against release build, or whatever defaults that might or might not use. (The OP never mentioned release build or what optimization level, which is why I wrote behaviour would depend on that, plus compiler.) For simplicity I was comparing plain -O against -O.... They both differ with no -O at all. gcc went identical at -O onward, for msvc they still differ at plain -O, I had to go to -O1 to make them the same. Just saying.


  • Moderators

    @JonB Yeah, but no sane project uses that. MSVC has an established set of defaults for Release and Debug builds and most if not every build system uses that. Unless you care much for debug build performance (which is the case in some, admittedly small, set of cases) there's little worth in analyzing anything but Release configuration.



  • @Chris-Kawa
    The following is perhaps a conversation for another time/thread. We (originally) produced cross-platform tools (started a long time ago, not Qt). I gave up compiling with any optimization flags (any compiler, any platform) allowed back in the last millennium, as I could not deal with the bugged code (oh yes!) they generated which would show up under circumstances at customer sites. Ever since then I have never trusted any compiler's optimization flags, because the potential bug penalty outweighed any benefit I might gain in quicker code. We release our code stripped of debug but not compiler optimized. Do you (really) believe I should rethink now after all these years?!


  • Moderators

    I gave up compiling with any optimization flags

    That's truly horrible!

    Ever since then I have never trusted any compiler's optimization flags

    As I said - each compiler has an established set of options for their Release and Debug builds. Those are by far the most tested configs on the planet. If you're afraid of bugs that's where there's least of them.

    We release our code stripped of debug but not compiler optimized.

    That's unbelievably awful. I wish you hadn't told me that and I could go on not knowing that there's software released this way.

    Do you (really) believe I should rethink now after all these years?!

    Absolutely! Do that right this moment! :D No, seriously, the overhead you're imposing on your runtime if you don't enable optimizations is absurd - For example unoptimized STL in MSVC has often something like 20x overhead. Just look at that absolutely basic example above - you're using walls of code and function calls, thrashing cache and draining energy where you could do 2 very fast instructions!



  • @Chris-Kawa
    You are going over the top IMHO! Not optimizing is not that bad, despite what you say. I cannot comment on, say, STL in MSVC. Our apps are I/O bound in system code, file handling, database access etc., so local optimization (of our own code) is not going to be that significant over the whole experience.

    Your points are valid, but they do not address the reality of what we found: your code can be as optimized as you feel like, but that's useless if we/the user cannot trust the code because of empirical observation of bugged code generation under compiler optimization. Being burnt all those years ago has left a fear that perhaps you have never experienced.

    If I ever rethought the situation (you are inspiring me now!) I guess I would give optimization a go now. You are saying that you can guarantee that e.g. MSVC will not have a single bug in optimized code generated? Serious question.


  • Moderators

    You are going over the top! Not optimizing is not that bad

    Yes, yes it is. The user visible impact might not be that severe in some types of apps but the underlying waste is unquestionable. In particular cases, like gaming, it can drop a game from 120 frames per second to the lower 20s.

    Being burnt all those years ago has left a fear that perhaps you have never experienced.

    A horse looked at me the wrong way 20 years ago so i don't use cars and walk everywhere.

    You are saying that you can guarantee that e.g. MSVC will not have a single bug in optimized code generated?

    No, I can't guarantee that for any existing software. I can guarantee that config used by millions of apps will be better tested than config used by dozens.

    Serious question.

    Serious answer then - I'd bet that if you turned on optimization after years of not using them your software would crash a lot, finding bugs you didn't even knew were there. Debug builds for example zero out memory before use so you can be sure you have garbage pointers lurking if you don't do release builds. Threading and synchronization is another area where unoptimized builds tend to mask a lot of problems, because they just run slower and you don't see races that often.



  • @Chris-Kawa
    I respect what you suggest, and am grateful for food for thought/your experiences. (And, yes, if I were releasing a game/frame-rate-critical app the situation would be different.) Just to be clear, I did not say we release "debug" builds, I said we release compiling/linking not for debug (e.g. so no memory zeroing, nor memory debug functions, nor debug libraries) but equally not with any optimization (-O...) compilation.

    A horse looked at me the wrong way 20 years ago so i don't use cars and walk everywhere.

    Yep, I don't use horses ;-)

    Purely, purely OOI: is whatever software you develop used in-house, or is it sold to external customers where you cannot replicate their environment?


  • Moderators

    is whatever software you develop used in-house, or is it sold to external customers where you cannot replicate their environment?

    I'm a game developer so both. We do in-house tools, big and small, think from Notepad to Photoshop size, used by few hundreds of people locally at their stations and on a set of servers, and then the game itself goes to all sorts of PCs and consoles across millions of players around the world so a very diverse set of hardware and software configurations.



  • @Chris-Kawa
    Yeah, a rather different situation from us, "mission critical".

    Final question: now that you know I am not saying we release with any debug compilation/libraries/anything (which I agree would be terrible), only that we do not compile our own code with -O..., [plus it's not a game] are you willing to relax your condemnation a little, or am I still going to Hell in a handbasket? :)


  • Moderators

    a rather different situation from us, "mission critical".

    We "release" tools almost daily so If I cause a crash a large group of people can't do their work and that costs, so it's pretty mission critical too, although not life threatening. Well, maybe just mine when those angry people come to me :)

    If you're under some regulations then it's not on you. I know there are industries where changing a configuration can mean a year of retesting, reapproving and certification. A lot of aviation for example still uses languages and compilers from the 70s because of that fact. If your software can kill a patient because you flipped a flag then it definitely should not be an ad hoc decision.

    are you willing to relax your condemnation a little, or am I still going to Hell?

    I'm not saying you're going to hell. I'm just saying you're gonna have a lot of regrets lying on your death bed ;) White bears drowning, bees vanishing, Australia burning, all that life people wasted waiting for your software to finish...

    It's just a waste, that's all. A thing that can be done in microsecond you do in three. Nothing more, nothing less. It's the same as throwing out garbage on the pavement - it's not a world ending event, but how you feel about it is up to you.



  • For me the question is most OOI.

    While writing code I try to always choose the best solution,
    while this is not always possible, stuff like this is rarely documented and
    consistent so I appreciate everyone responding. You learn new stuff every day!



  • @Chris-Kawa said in Performance difference:

    I'm just saying you're gonna have a lot of regrets lying on your death bed ;)

    Believe me, one thing I will not be thinking about/regretting on my deathbed is whether I did or did not switch on a compiler optimization flag ;-)


  • Moderators

    @JonB It doesn't happen often but one switch can sometimes change the world. Anyways, I'm happy to see you confident in your future predicting abilities. Fingers crossed you're right.



  • @Chris-Kawa
    With your surname, are you from down-under?


  • Moderators

    @JonB Not sure what you mean. My last name is Polish and translates to coffee, which reminds me I'm up for a break :) Have a nice day.



  • @Chris-Kawa
    It looked a bit like "Kiwi" to me, I was way off. "("Down-under" means Australia or New Zealand.) It may be wasted on you, but the one thing I was thinking I might regret on my deathbed is that Kylie never chose to marry me. I do not believe that is because she is disappointed that I did not use compiler optimizations ;-) All the best :)


Log in to reply