合并写(write combining )
来源:互联网 发布:网络会员密码开锁 编辑:程序博客网 时间:2024/06/13 00:15
此文乃是翻译。。
原文地址:http://mechanical-sympathy.blogspot.com/2011/07/write-combining.html
墙内地址:http://ifeve.com/write-combining/
合并写(write combining )
现代CPU采用大量的技术来抵消内存访问延迟。 从DRAM存储中读取或者写入数据的时间CPU可以执行上百个指令。
用来降低这种延迟的主要手段是使用多层次的SRAM缓存。此外,也有SMP系统采用消息传递协议来实现缓存之间的一致性。即便如此,现代CPU是如此之快,是缓存根本无法企及的。因此,为了进一步降低延迟一些鲜为人知的缓冲区(buffers )也被使用。
本文探讨“合并写存储缓冲区(write combining store buffers)”,以及我们如何编写代码可以有效地使用它们。
CPU缓存是一个高效的非链式结构的hash map,每个桶(bucket)通常是64个字节。被称为之为一个“缓存行(cache line)”。缓存行(cache line)是内存传输的有效单元。例如,主存中地址A会映射到一个给定的缓存行C。
如果CPU需要访问的地址hash之后并不在缓存行(cache line)中,那么缓存中对应位置的缓存行(cache line)会失效,以便让新的值可以取代该位置的现有值。例如,如果我们有两个地址,通过hash算法hash到同一缓存行,那么新的值会覆盖老的值。
当CPU执行存储指令(store)时,它会尝试将数据写到离CPU最近的L1缓存。如果这时出现缓存失效,CPU会访问下一级缓存。这时无论是英特尔还是许多其他厂商的CPU都会使用被称为“合并写(write combining)”的技术。
当请求L2缓存行的所有权的时候,最典型的是将处理器的store buffers中某一项写入内存的期间, 在缓存子系统( cache sub-system)准备好接收、处理的数据的期间,CPU可以继续处理其他指令。当数据不在任何缓存层中缓存时,将获得最大的优势。
当连串的写操作需要修改相同的缓存行时,会变得非常有趣。在修改提交到L2缓存之前,这连串的写操作会首先合并到缓冲区(buffer)。 这些64字节的缓冲(buffers )维护在一个64位的区域中,每一个字节(byte)对应一个位(bit),当缓冲区被传输到外缓存后,标志缓存是否有效。
也许你要问如果程序要读取一些已被写入缓冲区(buffer)的数据,会发生什么事呢?我们的硬件会友好的处理,它们在读取缓存之前会先读取缓冲区。
这一切对我们的程序意味着什么呢?
如果我们可以在缓冲区被传输到外缓存之前能够填补这些缓冲区(buffers ),那么我们将大大提高传输总线的效率。如何才能做到这一点呢?大部分程序花费其大部分时间在循环的处理某项任务。
由于这些缓冲区的数量是有限的,并且它们根据CPU的型号有所不同。例如在Intel CPU,你只能保证在同一时间拿到4个。这意味着,在一个循环中,你不应该同时写超过4个截然不同的内存位置,否则你讲不能从合并写(write combining)的中受益。
代码如下:
- public final class WriteCombining {
- private static final int ITERATIONS = Integer.MAX_VALUE;
- private static final int ITEMS = 1 << 24;
- private static final int MASK = ITEMS - 1;
- private static final byte[] arrayA = new byte[ITEMS];
- private static final byte[] arrayB = new byte[ITEMS];
- private static final byte[] arrayC = new byte[ITEMS];
- private static final byte[] arrayD = new byte[ITEMS];
- private static final byte[] arrayE = new byte[ITEMS];
- private static final byte[] arrayF = new byte[ITEMS];
- public static void main(final String[] args) {
- for (int i = 1; i <= 3; i++) {
- out.println(i + " SingleLoop duration (ns) = " + runCaseOne());
- out.println(i + " SplitLoop duration (ns) = " + runCaseTwo());
- }
- int result = arrayA[1] + arrayB[2] + arrayC[3] + arrayD[4] + arrayE[5] + arrayF[6];
- out.println("result = " + result);
- }
- public static long runCaseOne() {
- long start = System.nanoTime();
- int i = ITERATIONS;
- while (--i != 0) {
- int slot = i & MASK;
- byte b = (byte) i;
- arrayA[slot] = b;
- arrayB[slot] = b;
- arrayC[slot] = b;
- arrayD[slot] = b;
- arrayE[slot] = b;
- arrayF[slot] = b;
- }
- return System.nanoTime() - start;
- }
- public static long runCaseTwo() {
- long start = System.nanoTime();
- int i = ITERATIONS;
- while (--i != 0) {
- int slot = i & MASK;
- byte b = (byte) i;
- arrayA[slot] = b;
- arrayB[slot] = b;
- arrayC[slot] = b;
- }
- i = ITERATIONS;
- while (--i != 0) {
- int slot = i & MASK;
- byte b = (byte) i;
- arrayD[slot] = b;
- arrayE[slot] = b;
- arrayF[slot] = b;
- }
- return System.nanoTime() - start;
- }
- }
这个程序在我的Windows 7 64位英特尔酷睿i7860@2.8 GHz系统产生以下的输出:
- 1 SingleLoop duration (ns) = 14019753545
- 1 SplitLoop duration (ns) = 8972368661
- 2 SingleLoop duration (ns) = 14162455066
- 2 SplitLoop duration (ns) = 8887610558
- 3 SingleLoop duration (ns) = 13800914725
- 3 SplitLoop duration (ns) = 7271752889
上面的例子阐明:如果在一个循环中修改6个数组位置(对应6个内存地址),我们的程序运行时间明显长于拆分工作的方式,即是:先写前3个位置,后修改后3个位置的数据。
通过拆分循环,我们可以让程序用更少的时间完成更多的工作!欢迎来到神奇的“合并写(write combining)”。通过使用CPU架构的知识,正确的填充这些缓冲区,我们可以利用底层硬件加速我们的程序。
不要忘了超线程(hyper-threading),可能有2个逻辑线程在竞争同一个核的缓冲区。
- 合并写(write combining )
- 四、RxJava基础 ---合并操作(Combining Observables)
- 最大比合并算法 (Maximal Ratio Combining, MRC)
- HBase write写优化
- Write-Through(透写)和Write-Back(回写).
- write()二进制方式写文件
- windows live write写博客
- java8 write file 写文件
- MongoDB 写安全(Write Concern)
- MongoDB 写安全(Write Concern)
- Cache写机制:Write-through与Write-back
- Cache写机制:Write-through与Write-back
- Cache写机制:Write-through与Write-back
- Cache写机制:Write-through与Write-back
- Cache写机制:Write-through与Write-back
- Cache写机制:Write-through与Write-back
- Cache写机制:Write-through与Write-back
- Cache写策略 — write-through与 write-back
- GDB 结合Core File巧妙分析Crash原因
- winform编程设定listview选中行
- office转pdf java
- 好用的JQ日期時間選擇插件
- GCD简介
- 合并写(write combining )
- tuxedo执行tmloadcf问题解决
- TextFiled
- 成为Java高手的25个学习目标
- stream buffer原理
- openwrt添加已经支持的cpu的bsp
- 音频 属性详解(涉及采样率、通道数、位数、比特率、帧等)
- 富文本輸入框,NicEditxia
- String,CString,TCHAR*,char*之间区别和联系