C编译器优化与内存、线程和易变性相关的情况如何?

huangapple go评论87阅读模式
英文:

What happens during C compiler optimizations in relation to memory, threads and volatility?

问题

1.) 调试器为什么无法访问缓存内存?它不应该能够查看存储的变量吗?

2.) 为什么无法从SRAM访问缓存变量?

3.) 缓存中的变量是否因为流水线处理而无法访问,因此调试器不允许访问以避免潜在的不匹配?

4.) 为什么线程会被认为是灾难性的,但线程不是共享内存吗?为什么无法像RAM或硬盘一样将其视为缓存?
"例如,如果将一个原始变量声明为volatile,编译器将不允许将其缓存在寄存器中——这是一种常见的优化,如果该变量在多个线程之间共享,将会导致灾难性后果。"

7.) 所有编译器都使用相同的优化标准吗(如O1、O2、O3、O4参数)?

我尝试编译代码并查看变量,但在没有使用volatile的情况下无法在调试器中访问它们。我本来期望能够查看它们,但最终不得不使用volatile。真正让我困惑的是上述问题在一个解释中的综合讨论。

英文:

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:
https://stackoverflow.com/questions/246127/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.

答案1

得分: 1

1.) 为什么缓存内存对调试器不可用?它不应该能够查看L1-L4中存储的变量吗?

这不是真的。一切都取决于调试器如何获取内存。在某些系统上,它是不可用的,而在某些系统上,根据硬件的实现,它是可用的。

链接的答案不太精确,我稍后会详细解释。

2.) 为什么无法从SRAM访问缓存变量?

我不明白你的意思。在某些微控制器系统上,如果SRAM被缓存,那么处理器将无法看到硬件(例如DMA)所做的更改,除非你使缓存失效。但这个问题太不明确,无法回答。

3.) 缓存中的变量是否因为流水线而无法访问,因此调试器不允许访问以防止潜在的不匹配?

这个问题没有简单的答案,它取决于调试硬件。

4.) 他们提到线程会很危险,但线程不是共享内存吗?为什么与RAM或硬盘相比,这不能作为缓存来访问? "例如,如果将原始变量声明为volatile,编译器不允许将其缓存在寄存器中--这是一种常见的优化,如果该变量在多个线程之间共享,将会导致灾难性后果。"

在寄存器中的缓存与缓存内存没有任何关系。这意味着编译器可以将变量存储在寄存器中,并在不从内存中存储或读取的情况下执行操作。在线程之间共享变量要复杂得多。请阅读关于操作的原子性和线程同步机制的信息。

5.) C编译器的优化是什么?

编译器可以重新排列代码,优化掉读取或写入,甚至优化或删除变量或代码片段,如果生成的代码具有与源程序相同的可观察行为

6.) C编译器优化是如何阻止变量在调试器中可见的?

它可以简单地删除不需要的变量以达到相同的可观察行为。删除的变量将不会在调试器中可见。与删除的源代码行一样。此外,程序流程可能会不同,例如在某些行放置断点可能会变得不可能。

示例:

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

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

在可执行文件中的生成代码为:

main:
        mov     eax, 0
        ret

因此,函数bar和变量y将不会存在,因此它们将不会对调试器可见。

7.) 如何触发优化,是否可以创建自己的优化,还是这是所有编译器通用的标准(例如O1、O2、O3、O4参数)?

你可以使用编译器命令行选项指定你想要启用的特定优化。通常在调试时,你通常会选择-O0-Og。https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

所以,volatile更多地涉及到假设代码的任何位都可以在任何时刻知道变量的状态,因为当前位的代码外部机制可能已经修改了该值。

不,volatile只告诉编译器必须在每次使用之前从其存储器中读取对象,并在每次更改后写回。它不影响其他任何内容。

我认为你对“缓存”这个词有些混淆。

英文:

> 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".

答案2

得分: 0

我觉得你可能有点过于思考这个问题 C编译器优化与内存、线程和易变性相关的情况如何?

让我试着重新阐述一下volatile的目的:通过声明一个变量为volatile,你告诉编译器变量的值可以通过外部手段改变。在低级别(例如嵌入式)代码中,这可能表示一种像DMA(例如可以随时写入内存的外设)这样的机制。

从一个线程内部来看,来自其他线程的活动也属于外部活动,因此可以使用同样的“警告”机制。

关于编译器究竟实现了哪些优化取决于编译器本身和编译器的确切版本。

所以,volatile与处理器中可用的不同缓存相比,更多地是关于假设任何一部分代码都可以知道变量在任何时刻的状态,因为外部于当前代码片段的机制可能已经修改了该值。

英文:

I feel you may be over-thinking this a bit C编译器优化与内存、线程和易变性相关的情况如何?

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.

huangapple
  • 本文由 发表于 2023年6月29日 00:04:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76574936.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定