我已经了解到一些Intel/AMD CPU可以同时进行多次复用并添加SSE/AVX:
每个周期的FLOPS用于沙桥和haswell SSE2/AVX/AVX2.
我想知道如何在代码中做到最好,我也想知道它是如何在CPU内部完成的.我的意思是超标量架构.假设我想做一个很长的总和,如下面的SSE:
//sum = a1*b1 + a2*b2 + a3*b3 +... where a is a scalar and b is a SIMD vector (e.g. from matrix multiplication)
sum = _mm_set1_ps(0.0f);
a1 = _mm_set1_ps(a[0]);
b1 = _mm_load_ps(&b[0]);
sum = _mm_add_ps(sum, _mm_mul_ps(a1, b1));
a2 = _mm_set1_ps(a[1]);
b2 = _mm_load_ps(&b[4]);
sum = _mm_add_ps(sum, _mm_mul_ps(a2, b2));
a3 = _mm_set1_ps(a[2]);
b3 = _mm_load_ps(&b[8]);
sum = _mm_add_ps(sum, _mm_mul_ps(a3, b3));
...
Run Code Online (Sandbox Code Playgroud)
我的问题是如何将其转换为同时乘法并添加?数据可以依赖吗?我的意思是CPU可以_mm_add_ps(sum, _mm_mul_ps(a1, b1))同时执行还是在乘法中使用的寄存器和add必须是独立的?
最后,这如何适用于FMA(与Haswell)?是_mm_add_ps(sum, _mm_mul_ps(a1, b1))自动转换为单个FMA指令还是微操作?
根据维基百科,x86是一个CISC设计,但我也听说过/它是RISC.什么是正确的?我还想知道为什么它是CISC或RISC.什么决定设计是RISC还是CISC?它只是微处理器所具有的机器语言指令的数量,还是有任何其他决定架构的特性?
突然间Xcode在编译时把这个错误扔给了我:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_Format", referenced from:
objc-class-ref in WOExerciseListViewController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)
在做了一些研究之后,我可能会理解我正在使用的库与64位版本不兼容.但这很奇怪,因为我在相同的库中工作至少一周而没有一段时间内的编译问题.这两个库只是由一堆类组成的,当我从项目中删除它时,我遇到了同样的问题.由于我自己从未创建过库,我不知道如何找到我正在使用的库与64位兼容(?)我还尝试对目标面板下的架构进行以下更改:
但这些变化都不起作用.请问有人对此有所了解吗?谢谢
在最后几天,我观察到我的新工作站的行为,我无法解释.对此问题进行一些研究,INTEL Haswell架构以及当前的Skylake Generation 可能存在一个错误.
在编写可能的错误之前,让我先概述一下使用的硬件,程序代码和问题本身.
我目前正在运行Ubuntu 15.04 64位桌面版,安装最新更新和内核.除了使用这台机器开发CUDA内核和东西,我最近测试了一个纯C程序.该程序正在对相当大的输入数据集进行改进的ART.因此代码执行一些FFT并耗费相当长的时间来完成计算.我目前无法发布/链接到任何源代码,因为这是正在进行的无法发布的研究.如果您不熟悉ART,只需简单解释它的作用.ART是一种用于重建从计算机断层摄影机接收的数据以获得用于诊断的可见图像的技术.因此,我们的代码版本重建了大小为2048x2048x512的数据集.到目前为止,没有什么特别的,也没有涉及火箭科学.经过几个小时的调试和修复错误后,代码在参考结果上进行了测试,我们可以确认代码是否正常工作.代码使用的唯一库是标准的math.h.没有特殊的编译参数,没有额外的库可能带来额外的问题.
该代码使用一种技术来实现ART,以最小化重建数据所需的投影.因此,我们假设我们可以重建一个涉及25个投影的数据片.代码以12个内核上完全相同的输入数据启动.请注意,实现不是基于多线程,目前启动了12个程序实例.我知道这不是最好的方法,涉及正确的线程管理是强烈建议,这已经在改进列表:)
因此,当我们运行至少两个程序实例(每个实例在一个单独的数据切片上工作)时,结果是一些预测是随机的错误.为了让您了解结果,请参阅表1.请注意,输入数据始终相同.
只运行一个涉及CPU核心的代码实例,结果都是正确的.即使执行一些涉及一个CPU内核的运行,结果仍然是正确的.仅涉及至少两个或更多核心会生成结果模式,如表1所示.
好吧,花了相当长的时间来了解究竟出了什么问题.所以我们完成了整个代码,大多数问题都是以一个小的实现错误开始的.但是,嗯,没有(当然我们不能证明没有错误也不能保证它).为验证我们的代码,我们使用了两台不同的机器:
出人意料的是,这两个MACHINE1和机器2产生总是正确的结果.即使使用所有CPU核心,结果仍然是正确的.每台机器上超过50次运行甚至没有错误的结果.代码是在没有优化选项或任何特定编译器设置的每台目标机器上编译的.因此,阅读新闻导致以下发现:
因此,在Prime95和Mersenne社区的人们 似乎是第一批发现和识别这个讨厌的bug的人.引用的帖子和新闻支持怀疑,这个问题只存在于繁重的工作量下.根据我的观察,我可以确认这种行为.
作为一项学校作业,我需要找到一种方法来获取L1数据缓存行大小,而无需读取配置文件或使用api调用.假设使用内存访问读/写时序来分析和获取此信息.那我该怎么做呢?
在完成另一部分任务的不完整尝试中,为了找到缓存的级别和大小,我有:
for (i = 0; i < steps; i++) {
arr[(i * 4) & lengthMod]++;
}
Run Code Online (Sandbox Code Playgroud)
我想也许我只需要改变第2行,(i * 4)部分?所以一旦我超过缓存行大小,我可能需要更换它,这需要一些时间?但它是如此直截了当?所需的块可能已经存在于内存中?或者perpahs我仍然可以依靠这样一个事实:如果我有足够大的steps,它仍然可以非常准确地运作?
UPDATE
下面是对GitHub的尝试 ...主要部分如下
// repeatedly access/modify data, varying the STRIDE
for (int s = 4; s <= MAX_STRIDE/sizeof(int); s*=2) {
start = wall_clock_time();
for (unsigned int k = 0; k < REPS; k++) {
data[(k * s) & lengthMod]++;
}
end = wall_clock_time();
timeTaken = ((float)(end - start))/1000000000;
printf("%d, %1.2f \n", s * sizeof(int), timeTaken); …Run Code Online (Sandbox Code Playgroud) 我并不是真的想要优化任何东西,但我记得我一直都是从程序员那里听到的,我把它当作一个真理.毕竟他们应该知道这些东西.
但我想知道为什么除法实际上比乘法慢?分裂只是一个美化的减法,乘法是一个美化的加法吗?所以在数学上我不明白为什么一种方式或另一种方式在计算上有非常不同的成本.
任何人都可以澄清这个的原因/原因所以我知道,而不是我从其他程序员那里听到的,我之前询问的是:"因为".
任何人都可以解释什么是加载缓冲区以及它与失效队列的不同之处.以及存储缓冲区和写入组合缓冲区之间的区别?Paul E Mckenny的论文http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf 很好地解释了存储缓冲区和失效队列,但不幸的是没有谈到写入组合缓冲区
作为我的应用程序的一部分,我正在使用NDK,并想知道是否值得将x86和mips二进制文件与标准ARM二进制文件一起捆绑.
我认为最好的方法是跟踪用户实际拥有的内容,是否有API调用以获取处理器架构,以便将其传回我的Google分析实例?
谢谢
我对空间和时间局部的含义有点困惑.我希望通过一个数组示例来看它,这将有助于我更好地理解它.
在这样的例子中:A [0] [1],A [0] [2],A [0] [3] ......等
这是否证明了时间局部性?我看到同一行被多次访问但是在不同的偏移处...这是否意味着访问了不同的地址?
另外,我说的是这样的例子:A [1],A [2],A [3] ......等等
展示空间位置?
希望对实时代码中时空局部性如何工作的一些澄清将有助于我更好地理解它们.
只是好奇知道哪些CPU架构支持比较和交换原子基元?