Stories
Slash Boxes
Comments

SoylentNews is people

posted by Fnord666 on Sunday August 25 2019, @01:57PM   Printer-friendly
from the quite-the-contrary dept.

Submitted via IRC for SoyCow3196

Why const Doesn't Make C Code Faster

In a post a few months back I said it's a popular myth that const is helpful for enabling compiler optimisations in C and C++. I figured I should explain that one, especially because I used to believe it was obviously true, myself. I'll start off with some theory and artificial examples, then I'll do some experiments and benchmarks on a real codebase: Sqlite.

Let's start with what I used to think was the simplest and most obvious example of how const can make C code faster. First, let's say we have these two function declarations:

void func(int *x);
void constFunc(const int *x);

And suppose we have these two versions of some code:

void byArg(int *x)
{
  printf("%d\n", *x);
  func(x);
  printf("%d\n", *x);
}

void constByArg(const int *x)
{
  printf("%d\n", *x);
  constFunc(x);
  printf("%d\n", *x);
}

To do the printf(), the CPU has to fetch the value of *x from RAM through the pointer. Obviously, constByArg() can be made slightly faster because the compiler knows that *x is constant, so there's no need to load its value a second time after constFunc() does its thing. It's just printing the same thing. Right? Let's see the assembly code generated by GCC with optimisations cranked up:


Original Submission

 
This discussion has been archived. No new comments can be posted.
Display Options Threshold/Breakthrough Mark All as Read Mark All as Unread
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
  • (Score: 3, Insightful) by Ken_g6 on Sunday August 25 2019, @05:18PM (13 children)

    by Ken_g6 (3706) on Sunday August 25 2019, @05:18PM (#885243)

    Const function arguments won't make code faster. On the other hand, const constants really should, such as this:

    const int d=4;

    for(int i=0; i < 100; i++) {
        printf("%d\n", i/d);
    }

    i/d should get turned into i>>2.

    Starting Score:    1  point
    Moderation   +1  
       Insightful=1, Total=1
    Extra 'Insightful' Modifier   0  
    Karma-Bonus Modifier   +1  

    Total Score:   3  
  • (Score: 2, Insightful) by Anonymous Coward on Sunday August 25 2019, @05:26PM (3 children)

    by Anonymous Coward on Sunday August 25 2019, @05:26PM (#885249)

    JavaScript runs on the consumer end. Nobody gives a shit about how fast it because we don't fucking run it. As long as we get that sweet sweet data to the advertising server so we can sell targeted ads to the fucking idiot consumer. Nothing else matters.

    • (Score: 2) by maxwell demon on Sunday August 25 2019, @08:38PM (2 children)

      by maxwell demon (1608) on Sunday August 25 2019, @08:38PM (#885362) Journal

      And in which way are the properties of JavaScript relevant for the optimization of code written in C or C++?

      --
      The Tao of math: The numbers you can count are not the real numbers.
      • (Score: 1, Funny) by Anonymous Coward on Sunday August 25 2019, @09:25PM (1 child)

        by Anonymous Coward on Sunday August 25 2019, @09:25PM (#885384)

        You're not getting the message, snowflake. C is irrelevant because C is not used in the real world to sell targeted advertising. JavaScript makes money.

        • (Score: 0) by Anonymous Coward on Monday August 26 2019, @11:00AM

          by Anonymous Coward on Monday August 26 2019, @11:00AM (#885592)

          Still mining Monero on other people's computers? Tse, tse.

  • (Score: 2) by BsAtHome on Sunday August 25 2019, @05:38PM

    by BsAtHome (889) on Sunday August 25 2019, @05:38PM (#885259)

    In this *special* case, that would work. But only if you look at the loop variable 'i' and detect it to be strictly positive. Otherwise, shifting does not always act as you want for integers. Not all compilers distinguish between LSR and ASR. Therefore, you would want to use unsigned types, which are more narrowly defined.

    The other problem is that the constant declared integer 'd' has a memory allocation in the strict sense. It is declared non-static and must therefore be visible throughout the link-space as addressable and cannot be eliminated using substitution easily. Referring to 'd' in the code therefore requires a memory dereference.

    That brings us to the problem that you can take the address of 'd' (using &d) and have a (const int *) type. That means that 'd' /must/ be in addressable memory-space and cannot be substituted as a constant value in the division.

    Please note that declaring a 'const int' in your code is not the same as using #define. These are two totally different beasts of constructs with each their advantages and disadvantages. Do not get them mixed up.

  • (Score: 2, Informative) by Anonymous Coward on Sunday August 25 2019, @06:02PM (5 children)

    by Anonymous Coward on Sunday August 25 2019, @06:02PM (#885271)

    Well, let's see. With GCC 8.3.0, you get, (sorry, all the brackets removed, but I can't be arsed to HTML quote them for soylent crappy interface)


          0x0000000000000000 : push %rbp
          0x0000000000000001 : lea 0x0(%rip),%rbp # 0x8
          0x0000000000000008 : push %rbx
          0x0000000000000009 : xor %ebx,%ebx
          0x000000000000000b : sub $0x8,%rsp
          0x000000000000000f : nop
          0x0000000000000010 : mov %ebx,%esi
          0x0000000000000012 : mov %rbp,%rdi
          0x0000000000000015 : xor %eax,%eax
          0x0000000000000017 : add $0x1,%ebx
          0x000000000000001a : sar $0x2,%esi ---- HERE
          0x000000000000001d : callq 0x22
          0x0000000000000022 : cmp $0x64,%ebx
          0x0000000000000025 : jne 0x10
          0x0000000000000027 : add $0x8,%rsp
          0x000000000000002b : pop %rbx
          0x000000000000002c : pop %rbp
          0x000000000000002d : retq

    and without the const,


          0x0000000000000000 : push %rbp
          0x0000000000000001 : lea 0x0(%rip),%rbp # 0x8
          0x0000000000000008 : push %rbx
          0x0000000000000009 : xor %ebx,%ebx
          0x000000000000000b : sub $0x8,%rsp
          0x000000000000000f : nop
          0x0000000000000010 : mov %ebx,%esi
          0x0000000000000012 : mov %rbp,%rdi
          0x0000000000000015 : xor %eax,%eax
          0x0000000000000017 : add $0x1,%ebx
          0x000000000000001a : sar $0x2,%esi --- HERE
          0x000000000000001d : callq 0x22
          0x0000000000000022 : cmp $0x64,%ebx
          0x0000000000000025 : jne 0x10
          0x0000000000000027 : add $0x8,%rsp
          0x000000000000002b : pop %rbx
          0x000000000000002c : pop %rbp
          0x000000000000002d : retq

    Wow, so the same. Actually, not surprised at all. The compiler will determine if something can be changed by some lines of code and it's useless to have const. That's mostly for the programmer, not the compiler.

    • (Score: 0) by Anonymous Coward on Sunday August 25 2019, @08:09PM

      by Anonymous Coward on Sunday August 25 2019, @08:09PM (#885352)

      sorry, all the brackets removed, but I can't be arsed to HTML quote them for soylent crappy interface

      You could have used Unicode brackets instead:[]{}<>

    • (Score: 2) by maxwell demon on Sunday August 25 2019, @09:07PM (3 children)

      by maxwell demon (1608) on Sunday August 25 2019, @09:07PM (#885376) Journal

      For code there is <ecode>:

      Tags are <not> a problem </> if you use the right<tm/> tool for the job.

      Note: I did <em>not</em> encode the tags here (well, except in the line above the <ecode> block).

      --
      The Tao of math: The numbers you can count are not the real numbers.
      • (Score: 0) by Anonymous Coward on Monday August 26 2019, @08:04AM (2 children)

        by Anonymous Coward on Monday August 26 2019, @08:04AM (#885565)

        Good to know <;->

        • (Score: 0) by Anonymous Coward on Monday August 26 2019, @10:53AM (1 child)

          by Anonymous Coward on Monday August 26 2019, @10:53AM (#885590)

          C:/>

          • (Score: 0) by Anonymous Coward on Monday August 26 2019, @09:32PM

            by Anonymous Coward on Monday August 26 2019, @09:32PM (#885817)

            You unix kids and those wrong-way slashes.

  • (Score: 2, Informative) by Anonymous Coward on Sunday August 25 2019, @06:02PM (1 child)

    by Anonymous Coward on Sunday August 25 2019, @06:02PM (#885272)

    Any compiler worth it's salt should be able to identify constants and optimize accordingly regardless of whether they are declared as const or not.

    • (Score: 2) by FatPhil on Monday August 26 2019, @06:12AM

      by FatPhil (863) <reversethis-{if.fdsa} {ta} {tnelyos-cp}> on Monday August 26 2019, @06:12AM (#885536) Homepage
      Yes, in order to make this an example, it would need to have been an extern that the compiler couldn't know the value of at runtime. Except then all it would do would be a test of avoiding reloads of const externs, not of opcode substututions. And in the absence of a volatile, the const would give the compiler no greater optimising capabilities, so it wouldn't even be an example of that. (And yes, "const volatile" makes perfect sense.)
      --
      Great minds discuss ideas; average minds discuss events; small minds discuss people; the smallest discuss themselves