我见过他们中有很多人.NCache,Velocity等等,但我还没有找到比较它们的表格.
考虑以下标准,最好的是什么:
我知道GPU上的共享内存不会持久存在于不同的内核中.但是,L1缓存是否会在不同的内核调用中持续存在?
我正在寻找由ARM Cortex-A9处理器(如具有多个ARM A9处理器的Nvidia Tegra 2和Tegra 3)制造的SoC的L1访问延迟和L2访问延迟.
我可以找到一些关于这些架构的L1和L2大小的信息,但我对L1和L2访问延迟的信息不多.我发现的唯一可靠信息是"在Tegra 3上L2缓存延迟比2缓存2个周期快,而L1缓存延迟没有改变."
这里提到Tegra 2上的L2具有25个周期的延迟,并且这里提到L1具有4个周期的延迟并且L2具有31到55个周期的延迟.这些参考文献都不是完全可靠的.我希望能找到有关Nvidia,TI和Qualcomm网站和技术文档的更多信息,但没有成功.
编辑:OMAP4460和OMAP4470等类似SoC的信息也很棒.
我绝望地陷入了家庭作业问题,我希望能帮助你更好地理解它.这是我给的:
什么是有效的CPI?
据我所知,我需要计算每个缓存级别的未命中罚分.
现在我需要计算有效CPI.这是我有点困惑的地方.
我相信公式应该是:
CPI = BaseCPI +(%L1 MR/Instr*L1 Miss Misalty)+(%L1 MR/Instr*%L2 MR/Instr*L2 Miss Penalty)+(%Global MR/Instr*L3 Miss Penalty)
如果我这样做,我明白了
CPI = 2.0 +(0.07*30)+(0.07*0.3*60)+(0.03*300)= 14.36
在给我的导师发电子邮件后,因为班上没有人理解全球和地方的1-2分钟解释,我被告知我的答案很接近,但错了.如果有人能够提供一些见解,或者甚至指向一个好的教程,我将不胜感激.我可以理解如何计算1级和2级缓存的有效CPI.跳到3会让我感到困惑.
我的问题是关于本书中的以下短语:
不幸的是,SoA表格并非在所有情况下都是理想的.对于随机或不连贯的情况,收集用于访问数据,SoA表单可能导致额外的不需要的数据被读入缓存,从而降低性能.在这种情况下,使用AoS表单将导致更小的工作集和更高的性能.但是,通常,如果要对计算进行矢量化,则优选SoA形式.
我猜测 AoS可能导致更好性能的原因是,当同一结构中的不同或更好的所有字段都参与单个矢量化运行时.
示例(只是概念,没有具体或工作代码):
/*Note that the types of data I maintain the same intentionally,
to simplify discussion*/
struct Data {
float mean;
float distribution[10]
}
Run Code Online (Sandbox Code Playgroud)
并定义从某些数据源中随机获得的数组
Data aos[5];
现在,如果在矢量化循环期间我做了类似的事情:
float* dataPtr = &(aos[0].mean);
#pragma simd
for(int i=0; i< 60; i++)
{
const float mean = (*dataPtr);
/*do something with mean */
dataPtr++;
/*do something with distribution */
}
Run Code Online (Sandbox Code Playgroud)
这将导致更好的性能,因为在SoA的情况下,我将在高速缓存行上推送我在计算期间可能实际需要的更多信息.有些CPU预缓存?在AoS的情况下,相反会产生更好的性能.
我的假设是正确的,还是还有别的?
换句话说,L1,L2,L3等缓存是否总是反映其CPU的字节顺序?
或者总是将数据存储在某些特定字节序的缓存中更有意义吗?
是否有一般设计决定?
我正在生成一个合成C基准测试,旨在通过以下Python脚本导致大量的指令获取失败:
#!/usr/bin/env python
import tempfile
import random
import sys
if __name__ == '__main__':
functions = list()
for i in range(10000):
func_name = "f_{}".format(next(tempfile._get_candidate_names()))
sys.stdout.write("void {}() {{\n".format(func_name))
sys.stdout.write(" double pi = 3.14, r = 50, h = 100, e = 2.7, res;\n")
sys.stdout.write(" res = pi*r*r*h;\n")
sys.stdout.write(" res = res/(e*e);\n")
sys.stdout.write("}\n")
functions.append(func_name)
sys.stdout.write("int main() {\n")
sys.stdout.write("unsigned int i;\n")
sys.stdout.write("for(i =0 ; i < 100000 ;i ++ ){\n")
for i in range(10000):
r = random.randint(0, len(functions)-1)
sys.stdout.write("{}();\n".format(functions[r]))
sys.stdout.write("}\n")
sys.stdout.write("}\n")
Run Code Online (Sandbox Code Playgroud)
代码所做的只是生成一个C程序,该 …
这似乎是一个奇怪的问题..
假设缓存行的大小为64字节.此外,假设L1,L2,L3具有相同的高速缓存行大小(此后称它是英特尔的Core i7的情况下).
内存上有两个对象A,B其(物理)地址相隔N个字节.为简单起见,我们假设A它位于缓存边界上,也就是说,它的地址是64的整数倍.
1)如果N<64,当ACPU取出时,B也会读入缓存.因此,如果B需要,并且高速缓存行尚未被驱逐,CPU将B在很短的时间内获取.大家都很开心.
2)如果N>> 64(即远大于64),当A被CPU取出时,B不会被读入缓存行A.所以我们说"CPU不喜欢追逐指针",这是避免堆分配基于节点的数据结构的原因之一std::list.
我的问题是,如果N> 64但是仍然很小,比如N= 70,换句话说,A并且B不适合一个缓存行但不是太远,当A由CPU加载时,取出B需要相同数量的时钟当N大于64 时,它会花费多少个周期?
改写 - 当A加载时,让t表示提取的时间B,t(N = 70)远小于或几乎等于t(N = 9999999)?
我问这个问题是因为我怀疑t(N = …
我正在阅读有关Intel Core i7系统中可用的不同预取器的信息。我进行了实验,以了解何时调用这些预取器。
这些是我的发现
L1 IP预取器在3次高速缓存未命中后开始预取。它仅在缓存命中时预取。
L2相邻行预取器在第一个高速缓存未命中后开始预取,并在高速缓存未命中时预取。
L1 H / W(跨步)预取器在第一次高速缓存未命中后开始预取,并在高速缓存命中时进行预取。
我无法了解DCU预取器的行为。它何时开始预取或调用?它是否在缓存命中或未命中时预取下一个缓存行?
我在其中提到的英特尔文档披露-hw-prefetcher中进行了探索-DCU预取器将下一个缓存行提取到L1-D缓存中,但是在开始预取时没有明确的信息。
谁能解释DCU预取器何时开始预取?