对于尚未在缓存中的地址,CLFLUSH 如何工作?

2024-02-05

我们正在尝试使用 Intel CLFLUSH 指令在用户空间刷新 Linux 中进程的缓存内容。

我们创建一个非常简单的 C 程序,首先访问一个大数组,然后调用 CLFLUSH 刷新整个数组的虚拟地址空间。我们测量 CLFLUSH 刷新整个数组所需的延迟。程序中数组的大小是一个输入,我们将输入从 1MB 更改为 40MB,步长为 2MB。

根据我们的理解,CLFLUSH 应该刷新内容在缓存中。因此,我们期望看到刷新整个数组的延迟首先随数组的大小线性增加,然后在数组大小大于 20MB(即我们程序的 LLC 的大小)后延迟应该停止增加。

然而实验结果却相当令人惊讶,如图所示。当数组大小大于 20MB 后,延迟不会停止增加。

我们想知道,如果该地址尚未在缓存中,那么在 CLFLUSH 将地址从缓存中刷新之前,CLFLUSH 是否可能会引入该地址? 我们还尝试在Intel软件开发人员手册中进行搜索,但没有找到任何关于如果地址不在缓存中CLFLUSH将做什么的解释。

下面是我们用来绘制该图的数据。第一列是数组的大小(以 KB 为单位),第二列是刷新整个数组的延迟(以秒为单位)。

任何建议/意见都非常感激。

[修改的]

前面的代码是不必要的。 CLFLUSH 在用户空间中可以更容易地完成,尽管它具有相似的性能。所以我删除了那些乱七八糟的代码,以免造成混乱。

SCENARIO=Read Only
1024,.00158601000000000000
3072,.00299244000000000000
5120,.00464945000000000000
7168,.00630479000000000000
9216,.00796194000000000000
11264,.00961576000000000000
13312,.01126760000000000000
15360,.01300500000000000000
17408,.01480760000000000000
19456,.01696180000000000000
21504,.01968410000000000000
23552,.02300760000000000000
25600,.02634970000000000000
27648,.02990350000000000000
29696,.03403090000000000000
31744,.03749210000000000000
33792,.04092470000000000000
35840,.04438390000000000000
37888,.04780050000000000000
39936,.05163220000000000000

SCENARIO=Read and Write
1024,.00200558000000000000
3072,.00488687000000000000
5120,.00775943000000000000
7168,.01064760000000000000
9216,.01352920000000000000
11264,.01641430000000000000
13312,.01929260000000000000
15360,.02217750000000000000
17408,.02516330000000000000
19456,.02837180000000000000
21504,.03183180000000000000
23552,.03509240000000000000
25600,.03845220000000000000
27648,.04178440000000000000
29696,.04519920000000000000
31744,.04858340000000000000
33792,.05197220000000000000
35840,.05526950000000000000
37888,.05865630000000000000
39936,.06202170000000000000

你想看看Skylake的新优化指南,Intel推出了另一个版本的clflush,称为clflush_opt,它是弱有序的,在你的场景中会表现得更好。

请参阅此处的第 7.5.7 节 -http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf

一般来说,CLFLUSHOPT 吞吐量高于 CFLUSH, 因为 CLFLUSHOPT 根据较小的一组进行排序 内存流量如上文和第 7.5.6 节所述。这 CLFLUSHOPT 的吞吐量也会有所不同。使用 CLFLUSHOPT 时, 刷新修改的缓存线将经历比 在未修改状态下刷新缓存行。 CLFLUSHOPT将提供 对于任何一致性的缓存行,性能均优于 CFLUSH 状态。 CLFLUSHOPT 更适合刷新大缓冲区(例如 大于许多 KBytes),与 CFLUSH 相比。在单线程中 应用程序中,使用 CLFLUSHOPT 的刷新缓冲区可能高达 9X 比使用带有 Skylake 微架构的 CFLUSH 更好。

本节还解释了刷新修改数据的速度较慢,这显然来自于写回惩罚。

至于增加的延迟,您是否正在测量遍历地址范围并清除每行所需的总时间?在这种情况下,即使数组大小超过了 LLC 大小,您也会线性依赖于数组大小。即使这些行不存在,clflush 也必须由执行引擎和内存单元处理,并查找每行的整个缓存层次结构,即使它不存在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对于尚未在缓存中的地址,CLFLUSH 如何工作? 的相关文章

  • 从 C# 调用非托管 dll。拿2

    我编写了一个 C 程序 它调用一个 C DLL 将命令行参数回显到文件中 当使用 rundll32 命令调用 c 时 它显示命令行参数没有问题 但是当从 c 内部调用它时 它不会显示 我问了这个问题 https stackoverflow
  • 使用 getopt_long (C++) 如何为两个需要参数编写长选项和短选项?

    include
  • 如何查找boost运行时版本

    我正在编写一个使用 boost 的 C 库 在这个库中 我想包含有关用于编译我的库的二进制版本的 boost 版本的信息 我可以使用宏BOOST VERSION这很好 我还想确定哪个是 boost 的运行时版本 以便我可以与用于编译我的库的
  • 每个 CPU 核心处于 C0 电源状态的时间

    任何帮助弄清楚如何做到这一点都会很棒 在过去一秒内 每个 CPU 核心处于 C0 电源状态的时间有多少 这是针对 Mac 应用程序的 因此需要 Objective C cocoa 和 c OS X 没有任何公开 CPU c 状态的 API
  • VBA 中的 VSTO:AddIn.Object 有时不返回任何内容 (null)

    Given VSTO 插件 An override object RequestComAddInAutomationService 它返回一个名为的类的实例Facade在我的场景中 Excel 2007 中的 VBA 宏可访问AddIn O
  • Code First - 实体框架 - 如何公开外键

    我有以下数据对象 public class Customer System Data Entity ModelConfiguration EntityTypeConfiguration
  • 使用 C 创建立体声正弦波

    我正在尝试用 C 创建立体声正弦 WAV 并且可能有不同的 可能是空白的 左声道和右声道 使用此函数为每个通道生成一个音调 int16 t create tone float frequency float amplitude float
  • 是否可以用 C# 为 Android 编写应用程序?

    我们都知道Android运行Dalvik VM程序 通常开发人员用 Java 编写程序并将其编译为 Dalvik 字节码 我想知道是否有可能创建一个可以接受 C 代码并将其编译为 Dalvik 字节码的编译器 嗯 这是一种选择 或者您可以在
  • 平衡两轮机器人而不使其向前/向后漂移

    我正在尝试设计一个控制器来平衡 2 轮机器人 约 13 公斤 并使其能够抵抗外力 例如 如果有人踢它 它不应该掉落 也不应该无限期地向前 向后漂移 我对大多数控制技术 LQR 滑模控制 PID 等 都很有经验 但我在网上看到大多数人使用 L
  • Xamarin 无法从异步获取实例

    我编写了一个通过蓝牙连接到 ESP32 的 Xamarin Forms 应用程序 现在我想从 MainPage xaml 页面的 CustomControl JoystickControl 获取值 我已经这样尝试过了 MainPage xa
  • 读取所有进程内存以查找字符串变量c#的地址

    我有 2 个用 C 编写的程序 第一个名为 ScanMe 的程序包含一个包含值 FINDMEEEEEEE 的字符串变量 以及一个值为 1546 22915487 的双精度变量 另一个名为 MemoryScan 的程序读取第一个程序的所有内存
  • 为什么 MISRA:2012 需要函数原型?

    我想知道为什么 MISRA 2012 需要函数原型 在下面的示例中 这两个原型并不是真正必要的 include
  • 如何在 Xamarin.Mac 中执行终端命令并读入其输出

    我们正在编写一个 Xamarin Mac 应用程序 我们需要执行像 uptime 这样的命令 并将其输出读取到应用程序中进行解析 这可以做到吗 在 Swift 和 Objective C 中都有 NTask 但我似乎无法在 C 中找到任何示
  • 如何带参数调用外部程序?

    我想在我的代码中调用一个 Windows 程序 并使用代码本身确定的参数 我不想调用外部函数或方法 而是调用 WinXP 环境中的实际 exe 或批处理 脚本文件 C 或 C 将是首选语言 但如果使用任何其他语言更容易完成此操作 请告诉我
  • 为什么 OOP 中静态类的最佳实践有所不同?

    我目前正在阅读有关 Java 最佳实践的内容 我发现根据这本书 https rads stackoverflow com amzn click com 0321356683我们必须优先选择静态类而不是非静态类 我记得在 C 最佳实践中 我们
  • 如何从标准输入读取一行,阻塞直到找到换行符?

    我试图从命令行的标准输入一次读取任意长度的一行 我不确定是否能够包含 GNU readline 并且更喜欢使用库函数 我读过的文档表明getline应该可以工作 但在我的实验中它不会阻塞 我的示例程序 include
  • 更新插入 MongoDB 时如何防止出现“_t”字段?

    我有一个应用程序 它使用 MongoDB 的 C 驱动程序将 Upsert 插入 MongoDB 数据库 当我打电话给Update函数 我无法指定我要更新的类型 然后 t字段插入元素的类型 这是我用来更新插入的代码 collection U
  • 什么是多重重继承?

    我将以下称为 多重重新继承 直接继承一个类一次 并通过继承其一个或多个后代来间接继承一次或多次 通过继承一个类的两个或多个后代来间接继承一个类两次或多次 我想知道它是否存在以及如何明确访问嵌入的子对象 1 Professional C 2n
  • lambda 表达式是多线程的吗?

    lambda 表达式是多线程的吗 假设当你将数学公式编写为 lambda 方法时 当你将其传递给另一个方法时 它会是多线程的吗 不是100 清楚你问的是什么 您是否想问 lambda 是否自然地在不同的线程上运行 如果是这样 则它们只是 S
  • 组合框由于某种原因被链接

    我有以下代码来填充 3 个组合框 private void PopulateDDLs SqlConnection connection SqlCommand command SqlDataReader reader DataTable dt

随机推荐