How to organize the code without losing performance?

6

Using functions instead of putting the code directly influences the performance of a program? For example:

void minhafuncao(){
  printf("Funcao");
}
main(){
  minhafuncao();
}

instead of

main(){
  printf("Funcao");
}

I know macros have a higher performance than functions, but so far I've only seen macros with arithmetic operations. Is it possible to place code blocks with multiple commands in a macro? Or, if not, some other way to make it perform better?

    
asked by anonymous 09.04.2015 / 17:45

2 answers

10
  

Using functions instead of putting code directly influences a program's performance very much?

No! Function calls, even more in C, are quite fast. There are many other things that will make your program much slower than a function call:

Asyoucanseeinthisimage,asingleaccesstotheharddiskspendsatimeequivalenttomillionsoffunctioncalls.Anaccesstoaremotecomputerisnoteventalkedabout.

Andevenifthefunctioncallswereslow,(whichtheyarenot)thebenefittheyofferintermsofcodeabstractionandorganizationisverylargeandwouldnotbeworthgivingupinthenameof"performance" . When it comes to optimizing a program, what makes a difference is the performance of "bottlenecks": if you have an internal loop consuming 90% of its execution time, doubling its speed will have a significant effect. On the other hand, if a snippet of your code only runs a few hundred times, even if you make it instantaneous you will not save more than a few milliseconds. So always measure your program performance before you start optimizing it ! It's hard to predict in advance which parts of your program are the real bottlenecks and any optimization out of the bottleneck is a waste of time that only serves to make your code more complicated. Not to mention that some optimizations may end up leaving your program slower than before. The only way to protect yourself from this is to always measure before and after any optimization you make.

  

I know macros perform better than functions

Not always! Macros are a manual form of inlining and the overuse of this technique greatly increases the size of the executable. In addition to wasting memory, this can increase the cache miss rate, which is quite detrimental to performance (an access to RAM requires hundreds of cycles).

In addition, the real performance gain of inlining comes from the cost of the function call, but rather from the opportunities that the optimizer now has to specialize the subroutine code to the call location (better allocation of registers, dead code, etc.). This does not always turn out to be worthwhile and so I recommend relying on your compiler instead of doing inlining in hand.

    
09.04.2015 / 18:07
6

At first it influences performance. But it may not influence by a number of factors.

A call to a function, in addition to the instructions for deviation and return of the flow of the program to another address, there may be a copy of the parameters, either from memory to memory or through registers. So it's cost, of course.

If the function is simple and depending on the options used to compile the program the function will be optimized through the inline expansion . That is, if advantageous, the compiler removes the call from the function and places its code where the call was made. Note that the compiler knows that there are cases where using this technique will produce the opposite result.

This does the same thing the macro would do but much better. At first the compilers were not able to do this and the macros had this advantage, despite the disadvantages that this feature has. Today there are no major reasons for using the macro, only very specific situations require its use in C-code and still less in C ++ code that has even better features.

It is possible to make macros more complex than simple arithmetic operations but is not recommended for use today. But as I said before macros do not understand the context where they are running, this can cause problems if care is not taken in their creation and / or use.

Example:

#define exemplo() \
  do { \
    faz alguma coisa aqui \
  } while (0)

Today you have no more reason to do this. Today even in C, most of the time the programmer should be concerned with the readability of the code and not with the performance. The compiler will make the code be as fast as possible in the vast majority of situations that the code is well written. You do not have to be looking for the best ways to write thinking primarily about performance. When the performance is not enough, then one must think about what to do to improve that stretch. rarely will the macro be the solution for this case.

In almost 100% of cases the compiler will know if a function must be "linearized" for better performance. If he does not do this is because he understands that there will be no gain and he hits more than programmers usually do.

It seems to me that some compilers may force inline , through a specific flag even when it is not recommended. Almost always when the programmer wants to be smarter than the compiler, it fails.

Your example is sure to be "linearized," unless the compiler is told not to do it. But a small change that will still leave the short function will probably prevent this from happening:

void minhafuncao(){
  for (int i = 0; i < 100; i++) printf("Funcao");
}

Probably the time spent inside the function is large enough for the compiler to understand that there will be no gain. But other factors can be taken into account for evaluation.

I will not go into details of what is done or not because I do not know deeply and depends on implementation, that is, it can change in each version or brand of the compiler.

A test can be applied to see if there is a difference or not:

#include <stdio.h>
#include <time.h>

int minhafuncao(){
    int x = 0;
    x++;
    return x;
}

int main () {
    clock_t begin, end;
    double time_spent;
    int x;

    begin = clock();
    for (int i = 0; i < 300000000; i++);
    end = clock();
    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf ("Tempo gasto %.2lf segundos.\n", time_spent);

    begin = clock();
    for (int i = 0; i < 300000000; i++) minhafuncao();
    end = clock();
    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf ("Tempo gasto %.2lf segundos.\n", time_spent);

    begin = clock();
    for (int i = 0; i < 300000000; i++) x++;
    end = clock();
    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf ("Tempo gasto %.2lf segundos.\n", time_spent);
    x++;
    return 0;
}

Ideone is not the best environment to take the test , but you can get an idea. I recommend doing your test. The result may be different under different conditions.

Another test without returning a value. Notice how it changes.

    
09.04.2015 / 18:03