首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从MMIO预取吗?

从MMIO预取吗?
EN

Stack Overflow用户
提问于 2022-11-12 01:03:22
回答 1查看 122关注 0票数 4

是否可以为PCIe栏中由MMIO区域支持的地址(并通过UC或WC页表条目进行映射)预取?我目前正在为这个地址发出一个负载,这会导致超线程延迟相当一段时间。通过PREFETCHNTA有一个非时态访问提示,所以这似乎是可能的。

如果可能的话,您知道预取值存储在哪里吗?在我能够为它发出负载之前,有什么可能导致它失效?例如,如果我为一些无关的东西发出同步指令(如sfence ),这会导致预取值失效吗?

来自英特尔软件开发手册:

“忽略来自不可缓存或WC内存的预取。应该指出,处理器可以自由地从分配给内存类型的系统内存区域(即WB、WC和WT内存类型)中获取和缓存数据。”

MMIO区域所在的PCIe条被标记为预取,因此我不确定这是否意味着,鉴于上面的手册中的语言,预取将使用它。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-20 00:24:03

我要感谢彼得·科德斯、约翰·D·McCalpin、尼尔·纳图、克里斯蒂安·路德洛夫和大卫·马齐埃,感谢他们帮助我解决这个问题!

为了预取,您需要能够将MMIO读取存储在CPU缓存层次结构中。当您使用UC或WC页表项时,您不能这样做。但是,如果使用WT页表条目,则可以使用缓存层次结构。

唯一要注意的是,当您使用WT页表条目时,以前使用陈旧数据进行的MMIO读取可能在缓存中徘徊。您必须在软件中实现一致性协议,以从缓存中清除陈旧的缓存线,并通过MMIO读取读取最新数据。这在我的例子中是没有问题的,因为我控制了PCIe设备上发生的事情,所以我知道什么时候应该冲洗。但是,您可能不知道什么时候应该在所有场景中进行刷新,这可能会使这种方法对您毫无帮助。

以下是我如何设置我的系统:

  1. 将映射到PCIe栏的页面表条目标记为WT。您可以为此使用ioremap_wt() (如果条形图已经映射到内核中,则使用ioremap_change_attr() )。

  1. 根据https://sandpile.org/x86/coherent.htm,PAT类型和MTRR类型之间存在冲突。PCIe条的MTRR类型也必须设置为WT,否则PAT类型将被忽略。您可以使用下面的命令来完成此操作。确保使用PCIe栏地址(您可以在lspci -vv中看到)和PCIe栏大小更新命令。大小是以字节为单位的十六进制值。

代码语言:javascript
运行
复制
echo "base=$ADDRESS size=$SIZE type=write-through" >| /proc/mtrr

  1. 作为一种快速检查,此时您可能希望在循环中发出大量MMIO读取到条形图中相同的缓存行。您应该看到,在第一次MMIO读取之后,每个MMIO读取的成本会大幅下降。由于需要从PCIe设备获取值,所以第一次读取MMIO的代价仍然很高,但是后续的读取应该要便宜得多,因为它们都是从缓存层次结构读取的。

  1. 现在可以将预取发送到PCIe栏中的地址,并将预取的缓存行存储在缓存层次结构中。Linux有prefetch()函数来帮助发出预取.

  1. 您必须在软件中实现一个简单的一致性协议,以确保从缓存中清除由PCIe条支持的陈旧缓存线。您可以使用clflush刷新陈旧的缓存行。Linux有clflush()函数来帮助解决这个问题.

这个场景中关于clflush的一个注意事项:由于内存类型是WT,所以每个存储都会同时进入缓存中的缓存行和MMIO。因此,从CPU的角度来看,缓存中缓存行的内容总是与MMIO的内容相匹配。因此,clflush只会使缓存中的缓存行失效--它也不会将陈旧的缓存行写入MMIO。

  1. 注意到,在我的系统中,我立即在clflush之后发出预取。但是,下面的代码不正确:

代码语言:javascript
运行
复制
clflush(address);
prefetch(address);

此代码不正确,因为根据https://c9x.me/x86/html/file_module_x86_id_252.html,预取可以在clflush之前重新排序。因此,预取可以在clflush之前发出,而当clflush发生时,预取可能会失效。

要解决这个问题,根据链接,您应该在cpuid和预取之间发出clflush

代码语言:javascript
运行
复制
int eax, ebx, ecx, edx;

clflush(address);
cpuid(0, &eax, &ebx, &ecx, &edx);
prefetch(address);

彼得·科德斯( Peter )表示,在上面发布一个lfence,而不是cpuid,就足够了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74409615

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档