C 易失性变量和高速缓存

发布于 2024-12-11 12:56:43 字数 379 浏览 5 评论 0原文

缓存是由缓存硬件对处理器透明地控制的,因此如果我们在C程序中使用易失性变量,如何保证我的程序每次都从指定的实际内存地址读取数据而不是缓存。

我的理解是,

  1. Volatile 关键字告诉编译器不应优化变量引用,而应按照代码中的编程方式读取变量引用。

  2. 缓存由缓存硬件透明地控制,因此当处理器发出地址时,它不知道数据是来自缓存还是内存。

因此,如果我需要每次需要时都读取内存地址,我如何确保它不是从缓存引用而是从所需地址引用?

不知怎的,这两个概念并不能很好地结合在一起。请澄清它是如何完成的。

(假设我们在缓存中有回写策略(如果需要分析问题))

谢谢, 微内核:)

Cache is controlled by cache hardware transparently to processor, so if we use volatile variables in C program, how is it guaranteed that my program reads data each time from the actual memory address specified but not cache.

My understanding is that,

  1. Volatile keyword tells compiler that the variable references shouldn't be optimized and should be read as programmed in the code.

  2. Cache is controlled by cache hardware transparently, hence when processor issues an address, it doesn't know whether the data is coming from cache or the memory.

So, if I have a requirement of having to read a memory address every time required, how can I make sure that its not referred from cache but from required address?

Some how, these two concepts are not fitting together well. Please clarify how its done.

(Imagining we have write-back policy in cache (if required for analyzing the problem))

Thank you,
Microkernel :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

树深时见影 2024-12-18 12:56:44

Wikipedia 有一篇关于 MTRR(内存类型范围寄存器)的非常好的文章,它适用于 x86 系列CPU。

总而言之,从 Pentium Pro 开始,Intel(和 AMD 复制)就有了这些 MTR 寄存器,可以在内存范围上设置未缓存、直写、写组合、写保护或写回属性。

从 Pentium III 开始,但据我所知,只有 64 位处理器真正有用,它们遵循 MTRR,但可以被页面属性表覆盖,页面属性表让 CPU 为每个内存页面设置内存类型。

据我所知,MTRR 的一个主要用途是图形 RAM。将其标记为写组合会更有效。这使得缓存可以存储写入,并放宽所有内存写入排序规则,以允许对显卡进行非常高速的突发写入。

但出于您的目的,您可能需要未缓存或直写的 MTRR 或 PAT 设置。

Wikipedia has a pretty good article about MTRR (Memory Type Range Registers) which apply to the x86 family of CPUs.

To summarize it, starting with the Pentium Pro Intel (and AMD copied) had these MTR registers which could set uncached, write-through, write-combining, write-protect or write-back attributes on ranges of memory.

Starting with the Pentium III but as far as I know, only really useful with the 64-bit processors, they honor the MTRRs but they can be overridden by the Page Attribute Tables which let the CPU set a memory type for each page of memory.

A major use of the MTRRs that I know of is graphics RAM. It is much more efficient to mark it as write-combining. This lets the cache store up the writes and it relaxes all of the memory write ordering rules to allow very high-speed burst writes to a graphics card.

But for your purposes you would want either a MTRR or a PAT setting of either uncached or write-through.

夜雨飘雪 2024-12-18 12:56:44

正如你所说,缓存对程序员来说是透明的。如果您通过对象的地址访问对象,系统保证您始终看到最后写入的值。如果缓存中存在过时的值,您可能会遇到的“唯一”问题是运行时损失。

As you say cache is transparent to the programmer. The system guarantees that you always see the value that was last written to if you access an object through its address. The "only" thing that you may incur if an obsolete value is in your cache is a runtime penalty.

七堇年 2024-12-18 12:56:44

易失性 确保每次需要时都能读取数据,而无需担心 CPU 和内存之间的任何缓存。但是,如果您需要从内存中读取实际数据而不是缓存数据,您有两种选择:

  • 制作一块不缓存所述数据的板。 则可能已经出现这种情况
  • 如果您对某些 I/O 设备进行寻址,使用绕过缓存的特定 CPU 指令, 。当您需要清理内存以激活可能的 SEU 错误时,可以使用此方法。

第二个选项的详细信息取决于操作系统和/或 CPU。

volatile makes sure that data is read everytime it is needed without bothering with any cache between CPU and memory. But if you need to read actual data from memory and not cached data, you have two options:

  • Make a board where said data is not cached. This may already be the case if you address some I/O device,
  • Use specific CPU instructions that bypass the cache. This is used when you need to scrub memory for activating possible SEU errors.

The details of second option depend on OS and/or CPU.

暖树树初阳… 2024-12-18 12:56:44

使用 _Uncached 关键字可能有助于嵌入式操作系统,例如 MQX

#define MEM_READ(addr)       (*((volatile _Uncached unsigned int *)(addr)))
#define MEM_WRITE(addr,data) (*((volatile _Uncached unsigned int *)(addr)) = data)

using the _Uncached keyword may help in embedded OS , like MQX

#define MEM_READ(addr)       (*((volatile _Uncached unsigned int *)(addr)))
#define MEM_WRITE(addr,data) (*((volatile _Uncached unsigned int *)(addr)) = data)
韶华倾负 2024-12-18 12:56:43

这里是固件开发者。这是嵌入式编程中的一个标准问题,也是一个困扰许多(甚至是非常有经验的)开发人员的问题。

我的假设是您正在尝试访问硬件寄存器,并且该寄存器值可能会随着时间而变化(无论是中断状态、定时器、GPIO 指示等)。

volatile 关键字只是解决方案的一部分,在许多情况下可能不是必需的。这会导致每次使用变量时都会从内存重新读取该变量(而不是由编译器优化或在多次使用时存储在处理器寄存器中),但无论正在读取的“内存”是实际的硬件寄存器,而缓存位置对于您的代码来说是未知的,并且不受 易失性 关键字的影响。如果您的函数只读取寄存器一次,那么您可能可以放弃易失性,但作为一般规则,我建议大多数硬件寄存器应定义为易失性

更大的问题是缓存和缓存一致性。这里最简单的方法是确保您的寄存器位于未缓存的地址空间中。这意味着每次访问寄存器时,都保证读/写实际的硬件寄存器而不是高速缓存。一种更复杂但可能性能更好的方法是使用缓存地址空间,并让您的代码针对此类特定情况手动强制缓存更新。对于这两种方法,如何实现这一点取决于架构,并且超出了问题的范围。它可能涉及 MTRR(针对 x86)、MMU、页表修改等。

希望有所帮助。如果我错过了什么,请告诉我,我会扩展我的答案。

Firmware developer here. This is a standard problem in embedded programming, and one that trips up many (even very experienced) developers.

My assumption is that you are attempting to access a hardware register, and that register value can change over time (be it interrupt status, timer, GPIO indications, etc.).

The volatile keyword is only part of the solution, and in many cases may not be necessary. This causes the variable to be re-read from memory each time it is used (as opposed to being optimized out by the compiler or stored in a processor register across multiple uses), but whether the "memory" being read is an actual hardware register versus a cached location is unknown to your code and unaffected by the volatile keyword. If your function only reads the register once then you can probably leave off volatile, but as a general rule I will suggest that most hardware registers should be defined as volatile.

The bigger issue is caching and cache coherency. The easiest approach here is to make sure your register is in uncached address space. That means every time you access the register you are guaranteed to read/write the actual hardware register and not cache memory. A more complex but potentially better performing approach is to use cached address space and have your code manually force cache updates for specific situations like this. For both approaches, how this is accomplished is architecture-dependent and beyond the scope of the question. It could involve MTRRs (for x86), MMU, page table modifications, etc.

Hope that helps. If I've missed something, let me know and I'll expand my answer.

泡沫很甜 2024-12-18 12:56:43

从你的问题来看,你有一个误解。
正如您所描述的,Volatile 关键字与缓存无关。

当为变量指定关键字易失性时,它会提示编译器不要进行某些优化,因为该变量可能会从程序的其他部分发生意外更改。

这里的意思是,编译器不应该重用已经加载到寄存器中的值,而是再次访问内存,因为寄存器中的值不能保证与内存中存储的值相同。

其余有关高速缓存的内容与程序员没有直接关系。

我的意思是 CPU 的任何高速缓存与 RAM 的同步是一个完全不同的主题。

From your question there is a misconception on your part.
Volatile keyword is not related to the cache as you describe.

When the keyword volatile is specified for a variable, it gives a hint to the compiler not to do certain optimizations as this variable can change from other parts of the program unexpectedly.

What is meant here, is that the compiler should not reuse the value already loaded in a register, but access the memory again as the value in register is not guaranteed to be the same as the value stored in memory.

The rest concerning the cache memory is not directly related to the programmer.

I mean the synchronization of any cache memory of CPU with the RAM is an entirely different subject.

糖果控 2024-12-18 12:56:43

我的建议是将页面标记为未由虚拟内存管理器缓存。
在 Windows 中,这是通过设置 PAGE_NOCACHE 来完成的当调用 VirtualProtect

出于某种不同的目的,SSE 2 说明具有_mm_stream_xyz防止缓存污染的说明,尽管我认为它们不适用于您的情况。

无论哪种情况,都没有可移植的方式在C中做你想做的事情;您必须使用操作系统功能。

My suggestion is to mark the page as non-cached by the virtual memory manager.
In Windows, this is done through setting PAGE_NOCACHE when calling VirtualProtect.

For a somewhat different purpose, the SSE 2 instructions have the _mm_stream_xyz instructions to prevent cache pollution, although I don't think they apply to your case here.

In either case, there is no portable way of doing what you want in C; you have to use OS functionality.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文