-2

I've been studying C and looking at the volatile keyword when optimizations made an appearance in the discussion. They mention there are compiler optimizations which the volatile keyword protects against so data is stored fresh compared to cached. I don't fully understand what the C compiler optimizations are doing and how it relates to various interconnected topics. All I understand is the data is in memory now so a debugger can view it as compared to cached. I understand cache memory as SRAM sitting inside the CPU, main memory as RAM outside of the CPU as well as a hard drive further outside of RAM and slow to access. There doesn't seem to be any topics on the compiler optimizations when I searched for it and It's made me curious with a few inter-related questions on this topic that no one seems to cover at once but would be helpful:

1.) Why isn't the cached memory available to a debugger? Shouldn't it be able to look through L1-L4 for the stored variable?

I found a similar discussion but I don't understand some of the concepts in full detail: Why is volatile needed in C? 2.) Why are caching variables not accessible from SRAM?

3.) Are variables in the cache not accessible because of pipelining so debuggers will not allow access to view due to potential mismatch?

4.) They mention threads would be disastrous but don't threads share memory and why isn't this accessible as cache as compared to RAM or hard drives? "For example, if you declare a primitive variable as volatile, the compiler is not permitted to cache it in a register -- a common optimization that would be disastrous if that variable were shared among multiple threads."

5.) Deleted

6.) Deleted

7.) Are optimizations standard across all compilers(The O1, O2, O3, O4 arg)?

I've tried compiling code and reviewing the variables but I could not access them in the debugger until using volatile. I was expecting the ability to view them but ended up having to use volatile but the real misunderstanding are the topics combined in one explanation as described above.

Bejewled
  • 5
  • 2
  • 3
    This is too broad. Please focus on a specific topic. – Eugene Sh. Jun 28 '23 at 16:10
  • **Debuggers and optimized code don't play well together.** If you're trying to debug optimized code, you typically need to debug at the assembly level. Which means you have to be able to figure out what the optimizer did with your code. – user3386109 Jun 28 '23 at 16:15
  • It's a broad question because nobody is linking these topics together so there are too broad of answers on specific topics needed to be answered for clarity of the compounded topics that are being used. – Bejewled Jun 28 '23 at 16:27
  • When people say "cached", they actually mean in a register. Not CPU caches. (Or if they did mean CPU cache, they're wrong; this is common misconception. See also [When to use volatile with multi threading?](https://stackoverflow.com/a/58535118)) – Peter Cordes Jun 28 '23 at 16:48
  • Thanks Peter, it's a bit confusing from a computer engineering perspective without clarification. – Bejewled Jun 28 '23 at 16:57
  • Still too many. This site is for single question and answers to it. – Rohit Gupta Jun 30 '23 at 04:13

2 Answers2

1

1.) Why isn't the cached memory available to a debugger? Shouldn't it be able to look through L1-L4 for the stored variable?

It is not the truth. Everything depends on how the debugger fetches the memory. On some systems it is not available, on some systems it is, depending of the implementation of the hardware.

The linked answer is not very precise I will elaborate later

2.) Why are caching variables not accessible from SRAM?

I do not understand what you mean. On some uC systems if the SRAM is cached then processor will not see changes made by the hardware (for example DMA) unless you invalidate the cache. But the question is too imprecise to answer

3.) Are variables in the cache not accessible because of pipelining so debuggers will not allow access to view due to potential mismatch?

This question doesn't have an easy answer and it depends on the debug hardware

4.) They mention threads would be disastrous but don't threads share memory and why isn't this accessible as cache as compared to RAM or hard drives? "For example, if you declare a primitive variable as volatile, the compiler is not permitted to cache it in a register -- a common optimization that would be disastrous if that variable were shared among multiple threads."

Caching in the register does not have anything in common with cache memory. It means that the compiler may store the variable in the register and do operations without storing or reading it from the memory. Sharing the variables between threads is much more complicated. Read about the atomicity of operations and thread synchronization mechanisms.

5.) What are the C compiler optimizations?

Compiler can rearrange the code, optimize out reads or writes or even optimize or (remove) variables or code fragments if the generated code will have the same observable behaviour as the the source program.

6.) How does the C compiler optimization not allow variables to be seen in a debugger?

It can simply remove the variable not needed to archive the same observable behaviour. The removed variable will not be seen by the debugger. Same as removed lines of source code. Also the program flow can be different making for example placing breakpoints at some lines impossible.

Example:

int bar(int y)
{
    return y*y;
}

int main(int argc, char **argv)
{
    int y = bar(argc);
}

The resulting code in the executable file to:

main:
        mov     eax, 0
        ret

So the function bar and variable y will not exist, thus they will not be visible to the debugger.

7.) How do you trigger optimizations and can you create your own or is this a standard across all compilers(The O1, O2, O3, O4 arg)?

You can specify using the compiler command line options what particular optimizations you want to enable. Generally when debugging you usually want -O0 or -Og. https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

So, volatile is much less about the different caches available in a processor than it is about assuming any bit of code can know the state of a variable at any moment, as mechanisms external to the current bit of code may have modified the value.

No, volatile only tells the compiler that the object has to be read from its storage before every use and written back after every change. It does not affect anything else.

I think you are quite confused by the word "cached".

0___________
  • 60,014
  • 4
  • 34
  • 74
0

I feel you may be over-thinking this a bit :-)

Let me try to start by restating the purpose of volatile: by declaring a variable volatile, you indicate to the compiler that the value of the variable may change by external means. In low-level (eg embedded) code this can indicate a mechanism like DMA (like a peripheral that can write into the memory at any time).

From within one thread, activities from other threads are also external activities, so the same "warning" mechanism can be used there.

Regarding what optimizations the compiler exactly implements depends on the compiler itself and the exact version of the compiler.

So, volatile is much less about the different caches available in a processor than it is about assuming any bit of code can know the state of a variable at any moment, as mechanisms external to the current bit of code may have modified the value.

fvu
  • 32,488
  • 6
  • 61
  • 79