3

Is there a way to know how many instructions or resources are used by a variable or object inside the compiled executable?

For example, I would like to know how much space an empty std::vector<int> will use in the compiled binary file.

lucaboni
  • 2,334
  • 2
  • 29
  • 41
  • 1
    Yes. A variable doesn't use any instructions. – n. m. could be an AI Apr 04 '16 at 10:25
  • But the call to the constructor uses instructions. – Martin Bonner supports Monica Apr 04 '16 at 10:26
  • 4
    Asking this does not make much sense. What are you actually aiming for? – wilx Apr 04 '16 at 10:28
  • Whether it uses memory depends on how it is declared. If it is an automatic variable in a function that is not called: no, it does not use memory. – Martin Bonner supports Monica Apr 04 '16 at 10:29
  • I'm analyzing the impact of using some templates inside my code. So I'm wondering effectively how much space it really uses. – lucaboni Apr 04 '16 at 10:32
  • No chance! You can add some lines of code and measure the delta to the previous compilation. But adding some more lines can result in lesser code because of stopped inlining. There is no 1:1 relation between source and executable size. Data memory can be dumped from the file ( binutils on linux ). Runtime memory can seen from the os. – Klaus Apr 04 '16 at 11:00
  • @wilx consider [this](http://www.embedded.com/design/programming-languages-and-tools/4424383/A-guide-to-C--for-C-programmers), the paragraph about some compilers generating unnecessary permutations of templates, so in one of the (rare) contexts when code size is an issue, like embedded systems development, it may help to know how expensive certain design-time constructions are in terms of generated code size. – Cee McSharpface Apr 04 '16 at 11:11
  • Take `vector::size` as an example. It may very well be inlined as `(v._End - v._Begin)` which is rather trivial, but there's no reasonable way to connect exactly those instructions to the variable `v`.One important reason is because the `size()` call is typically used in a context, and the optimizer may very well arrange the outcome of `size()` to be stored in the register that's used as input for the next operation. Now the instruction which stores it there, it is considered part of the output of the first statement, or of the input of the next? – MSalters Apr 04 '16 at 11:12
  • @MSalters it will be hard to define at the least. That's why I suggested in my answer that a way to get practically useful measurements involves comparing the output of two alternatives, and not attempt to figure out the "net weight" of a variable/template/whatever in the generated code. – Cee McSharpface Apr 04 '16 at 11:25

2 Answers2

0

Tell the compiler to generate an assembly listing (compiler/linker options, depends on your compiler and platform). Then compile it once with, and once without the variable or object. Compare the number of lines in the two generated listings. This should give you the difference of instruction count.

EDIT: The measurement might not be 100% accurate due to various optimizations, alignment, code reordering. As @Klaus pointed out, paradox results may be seen when inlining tresholds are exceeded and produce smaller listings from more source.

EDIT: specifically in connection with C++ templates, see also Can we see the template instantiated code by C++ compiler

(You mentioned "inside the compiled executable", so I assume that you were asking about compile-time, not runtime).

Community
  • 1
  • 1
Cee McSharpface
  • 8,493
  • 3
  • 36
  • 77
  • This doesn't allow for the compiler including NOP or NOOP instructions. These are supported by some processors, to allow predictable timing of operations involving registers, processor status flags, or even memory access. It also doesn't allow for various ways in which compilers/optimizers reorder code. – Peter Apr 04 '16 at 10:37
  • That's a quite intrusive solution. By doing like that I'm effectively changing my source code. Isn't there a way to inspect the generated binary code? – lucaboni Apr 04 '16 at 10:40
  • @lucab0ni: Yes. Read its assembly. You'll need the ability to read assembly. – Lightness Races in Orbit Apr 04 '16 at 10:45
  • @Peter right - this solution will never be 100% accurate. it should give a rough measure of the impact though. – Cee McSharpface Apr 04 '16 at 10:46
  • Today's compiler will inline code scattering to the whole object. How should a assembler listing help here? – Klaus Apr 04 '16 at 10:57
  • @lucab0ni "I'm analyzing the impact of using some templates inside my code" > sure, you cannot simply remove them (they will be there for a reason, and other code will depend on it, probably heavily depend on it). But still, if you want to measure an impact, there is need for an alternative version of the code to compare to. – Cee McSharpface Apr 04 '16 at 10:58
  • @Klaus inlined code is code all the same. It counts towards the "impact of the variable" (whatever *that* is, though) – Cee McSharpface Apr 04 '16 at 11:01
  • @BarryTheHatchet should I use objdump to show the disassembly code and source code of the compiled object file? See http://stackoverflow.com/questions/137038/how-do-you-get-assembler-output-from-c-c-source-in-gcc – lucaboni Apr 04 '16 at 11:11
  • @lucab0ni: No, you should do what dlatikay said in this answer. – Lightness Races in Orbit Apr 04 '16 at 11:44
  • @dlatikay: You are totally wrong, inlined code is not the same copy at all places. The code at each position is optimized again. So it can be that at one place only a constant is propagated while on another place the complete algorithm is present. It depends on how the code is used, which return values are used and if the construct maybe generate only temporary effects and tons of other circumstances. – Klaus Apr 04 '16 at 12:43
  • @Klaus I did not mean to say that inlines translate to identical sequences of instructions at all places. Your concerns and corrections are all valid. I read the OP's question as "how much space will the compiled representation of take up in generated machine code", and from such a point of view it is clear a) that whatever intricate optimizations a compiler will perform, goes into the measurement; and b) that only comparisons of multiple source code alternatives will have any practical value, when we assume an optimize-for-size motivation behind this. – Cee McSharpface Apr 04 '16 at 14:19
-1

Authors of "C++ Templates The Complete Guide" book (6.6.4 chapter) suggested to use so called Tracer objects for similiar purposes.

It is quote:

"A tracer is a user-defined class that can be used as an argument for a template to be tested. Often, it is written just to meet the requirements of the template and no more than those requirements. More important, however, a tracer should generate a trace of the operations that are invoked on it. This allows, for example, to verify experimentally the efficiency of algorithms as well as the sequence of operations."

Simple example of tracer object:

#include <iostream>
#include <vector>

class TracerObject
{
public:
    TracerObject()
    {
       ++n_created;
    }
    ~TracerObject()
    {
       ++n_destroyed;
    }
    static int created_count(void)
    {
       return n_created;
    }
    static int destroyed_count(void)
    {
       return n_destroyed;
    }
    private:
    static int n_created;
    static int n_destroyed;
};

int TracerObject::n_created = 0;
int TracerObject::n_destroyed = 0;

int main(void)
{
   {
       std::vector<TracerObject> vector(2, TracerObject());
   }
   std::cout << "Constructor calls: " << TracerObject::created_count() << std::endl;
std::cout << "Destructor calls: " << TracerObject::destroyed_count() <<    std::endl;
    int i;
    std::cin >> i;
    return 0;
}
Alex Aparin
  • 4,393
  • 5
  • 25
  • 51