我需要运行 DAXPY 线性代数核的时序。天真地,我想尝试这样的事情:
fill(X,operand_size);
fill(Y,operand_size);
double seconds = timer();
daxpy(alpha,X,Y,operand_size);
seconds = timer() - seconds;
如果需要,完整的代码链接位于末尾。
问题是,填充操作数 x 和 y 的内存访问将导致它们被放置在处理器缓存中。因此,在 DAXPY 调用中对内存的后续访问比在生产运行中实际访问要快得多。
我比较了两种解决这个问题的方法。第一种方法是通过clflush指令从所有级别的缓存中刷新操作数。第二种方法是读取一个非常大的数组,直到操作数条目被“自然地”从缓存中逐出。我对两者都进行了测试,这是带有大小为2048的操作数的单个DAXPY调用的运行时:
Without flush: time=2840 ns
With clflush: time=4090 ns
With copy flush: time=5919 ns
这是几秒钟后进行的另一次运行:
Without flush: time=2717 ns
With clflush: time=4121 ns
With copy flush: time=4796 ns
正如预期的那样,刷新会增加运行时。但是,我不明白复制刷新如何导致 DAXPY 例程的运行时间大大延长。clflush 指令应从所有缓存中逐出操作数,因此 clflush 的时间应该是任何其他缓存刷新过程的执行时间的上限。不仅如此,刷新的计时(对于两种方法)也会反弹很多(数百纳秒,而对于未刷新的情况,则不到10纳秒)。有谁知道为什么手动刷新在运行时会有如此大的差异?
附录
完整的代码,包括所有的计时程序和刷新程序,在这里(194行):
http://codepad.org/hNJpQxTv
这是我的gcc版本。代码是用-O3选项编译的。(我知道,是老了;我必须构建的一些软件与较新的gcc不兼容)
使用内置规格。
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5646.1~2/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5646) (dot 1)
我在Mac OS X 10.6上使用Intel Xeon 5650处理器。
CPU为正常读取实际执行的操作(部分)的伪代码(在基准测试期间经常发生)可能是:
if( cache line is not in cache ) {
if(cache is full) {
find cache line to evict
if( cache line to evict is in "modified" state ) {
write cache line to evict to slower RAM
}
set cache line to "free"
}
fetch the cache line from slower RAM
}
temp = extract whatever we're reading from the cache line
如果您使用CLFLUSH
刷新缓存,那么if(缓存已满)
将为false,因为CLFUSH
使缓存为空。
如果使用复制来刷新缓存,则If(缓存已满)
分支将为真,而If(缓存行已修改)
也将在一半时间为真(缓存的一半将包含复制期间读取的数据,另一半将包含在复制期间写入的数据)。这意味着,有一半的时间,您最终会执行<code>写缓存行以逐出到较慢的RAM。
执行写入缓存行以逐出 RAM
将消耗 RAM 芯片带宽,并影响从较慢的 RAM 获取缓存行
的性能。
问题内容: 线程1:正在执行此循环 线程2将运行错误设置为假如果运行是易失性变量,则线程1退出循环并显示“完成”。 我的问题是,如果运行不是易失的,那么Thread1何时从主内存中读取运行变量? 注意:我很了解同步和volatile变量之间的关系,但是即使运行不是volatile或同步的,线程1也会停止。所以我的问题是,鉴于没有同步或没有波动,线程1什么时候决定从主存储器读取数据 问题答案: 这在
我的应用程序的写入吞吐量很低,我可以管理2-3分钟的更改,以反映在solr搜索结果中 目前,我通过索引应用程序进行提交(在每批文档之后),并在solr端配置了以下内容: 选择配置的原因来自我对以下内容的理解: 我的应用程序被大量读取需要大量缓存,我负担不起刷新缓存的费用。因此,我已经完全禁用了软提交。 我已经禁用了opensearch cher,因为如果我不这样做,它会使不可取的顶级缓存无效 在生
我在一个Spring多线程web服务上遇到了一个缓存问题,它有一个数据库后端和基于EHCache的缓存。该服务有许多客户端都在一次又一次地请求同一个对象,每秒钟有几十个请求。只有几个对象被频繁地请求,而大量其他对象被不频繁地请求。对象可以每隔几分钟改变一次,所以缓存的TTL设置为一分钟。从数据库加载对象很慢,至少需要几秒钟。 起初我使用了一个朴素的实现来获取对象: 检查对象是否在缓存中 如果是,则
Im有一个war项目,在wildfly上部署了JAX-RS接口,并配置了一个安全域,从db加载用户密码和角色。安全域使用缓存类型=默认值。安全域无法识别经过身份验证的用户的更新,因为旧数据会被缓存。我用jboss cli验证了这一点。sh.那么如何从缓存中删除特定用户呢?我希望在部署的应用程序中执行此操作,而不是通过jboss cli。嘘。
问题内容: 我在具有数据库后端和基于EHCache的缓存的Spring多线程Web服务上遇到缓存问题。该服务有许多客户端一次又一次地请求同一个对象,每秒有数十个请求。仅频繁请求几个对象,而不经常请求大量其他对象。对象可以每隔几分钟更改一次,因此将缓存的TTL设置为一分钟。从数据库加载对象很慢,并且至少需要几秒钟。 首先,我使用了一个简单的实现来获取对象: 检查对象是否在缓存中。 如果是,请从缓存中
演示一个问题的简化示例是 如果有的话,有什么方法可以保证journald收到?