此实现中是否承诺缓存失效
Is cache invalidation promised in this implementation
考虑以下代码:
volatile uint32_t word;
for (i=0; i<10; i++)
{
word = *(uint32_t *)(ADDRESS_IN_MEMORY);
printf("%"PRIu32, word);
some_function_compiled_in_other_object(); /* this function may or may not change memory content at adress ADDRESS_IN_MEMORY */
}
所以,由于 word
是易变的,我们知道 word = *(uint32_t *)(ADDRESS_IN_MEMORY)
确实会执行 10 次。但是,这里有关于系统缓存的承诺吗?我希望编译后的代码每次从该地址读取时都会使 ADDRESS_IN_MEMORY
before\after 无效,因此 word
将从系统内存而不是缓存中加载值。这是答应了吗?
答案是否取决于编译器是否知道 some_function_compiled_in_other_object
在内存地址 ADDRESS_IN_MEMORY
处更改值?
So, since word is volatile, we know that word = *(uint32_t *)(ADDRESS_IN_MEMORY) will be indeed executed 10 times.
没有
假设CPU有一些寄存器(并且只允许传送值to/from寄存器,不允许数据直接从内存中的一个地方传送到内存中的另一个地方) ,编译后的代码实际上做了更多类似这样的事情:
for (i=0; i<10; i++)
{
CPU_register_1 = *(uint32_t *)(ADDRESS_IN_MEMORY);
word = CPU_register_1
现在我们还假设编译器优化了代码。它知道 *(uint32_t *)(ADDRESS_IN_MEMORY);
不是易变的,所以它可能会将其转换成这样的东西;
CPU_register_1 = *(uint32_t *)(ADDRESS_IN_MEMORY);
for (i=0; i<10; i++)
{
word = CPU_register_1
C 标准对高速缓存一无所知。它们是 C 语言范围之外的特定于应用程序的细节。
volatile
关键字只与编译器执行的优化有关。编译器需要确保对 volatile
限定变量的操作按特定顺序排序,而不是优化掉。
读取硬件寄存器时,必须始终使用volatile
,否则编译器会假定寄存器的内容自上次使用以来从未更改过。
因此,如果您的示例中的 ADDRESS_IN_MEMORY
是一个与地址相对应的数字,那么您就有一个错误,因为您将其读作 *(uint32_t *)(ADDRESS_IN_MEMORY);
。这个错误与缓存内存没有丝毫关系。
缓存内存处理由 CPU/branch 预测处理,而不是由编译器或 C 语言处理。因此,您不能直接从应用程序代码影响它,除非您访问可以指定行为的 MMU 寄存器。它当然是非常系统特定的。健全的系统设置不会将内存映射硬件寄存器访问加载到数据缓存中。
然而,您可以通过连续访问内存来编写缓存友好的代码,始终从上到下读取下一个相邻地址,没有任何可以更改访问顺序的分支。
考虑以下代码:
volatile uint32_t word;
for (i=0; i<10; i++)
{
word = *(uint32_t *)(ADDRESS_IN_MEMORY);
printf("%"PRIu32, word);
some_function_compiled_in_other_object(); /* this function may or may not change memory content at adress ADDRESS_IN_MEMORY */
}
所以,由于 word
是易变的,我们知道 word = *(uint32_t *)(ADDRESS_IN_MEMORY)
确实会执行 10 次。但是,这里有关于系统缓存的承诺吗?我希望编译后的代码每次从该地址读取时都会使 ADDRESS_IN_MEMORY
before\after 无效,因此 word
将从系统内存而不是缓存中加载值。这是答应了吗?
答案是否取决于编译器是否知道 some_function_compiled_in_other_object
在内存地址 ADDRESS_IN_MEMORY
处更改值?
So, since word is volatile, we know that word = *(uint32_t *)(ADDRESS_IN_MEMORY) will be indeed executed 10 times.
没有
假设CPU有一些寄存器(并且只允许传送值to/from寄存器,不允许数据直接从内存中的一个地方传送到内存中的另一个地方) ,编译后的代码实际上做了更多类似这样的事情:
for (i=0; i<10; i++)
{
CPU_register_1 = *(uint32_t *)(ADDRESS_IN_MEMORY);
word = CPU_register_1
现在我们还假设编译器优化了代码。它知道 *(uint32_t *)(ADDRESS_IN_MEMORY);
不是易变的,所以它可能会将其转换成这样的东西;
CPU_register_1 = *(uint32_t *)(ADDRESS_IN_MEMORY);
for (i=0; i<10; i++)
{
word = CPU_register_1
C 标准对高速缓存一无所知。它们是 C 语言范围之外的特定于应用程序的细节。
volatile
关键字只与编译器执行的优化有关。编译器需要确保对 volatile
限定变量的操作按特定顺序排序,而不是优化掉。
读取硬件寄存器时,必须始终使用volatile
,否则编译器会假定寄存器的内容自上次使用以来从未更改过。
因此,如果您的示例中的 ADDRESS_IN_MEMORY
是一个与地址相对应的数字,那么您就有一个错误,因为您将其读作 *(uint32_t *)(ADDRESS_IN_MEMORY);
。这个错误与缓存内存没有丝毫关系。
缓存内存处理由 CPU/branch 预测处理,而不是由编译器或 C 语言处理。因此,您不能直接从应用程序代码影响它,除非您访问可以指定行为的 MMU 寄存器。它当然是非常系统特定的。健全的系统设置不会将内存映射硬件寄存器访问加载到数据缓存中。
然而,您可以通过连续访问内存来编写缓存友好的代码,始终从上到下读取下一个相邻地址,没有任何可以更改访问顺序的分支。