考虑在x86 CPU上进行单个内存访问(单个读取或单个写入,而不是读取或写入)SSE指令.该指令访问16字节(128位)的存储器,访问的存储器位置对齐为16字节.
文档"英特尔®64架构内存订购白皮书"指出,对于"读取或写入地址在8字节边界上对齐的四字(8字节)的指令",内存操作似乎作为单个内存访问执行,而不管记忆类型.
问题:是否存在Intel/AMD/etc x86 CPU,它们保证读取或写入与16字节边界对齐的16字节(128位)作为单个内存访问执行?是这样,它是哪种特定类型的CPU(Core2/Atom/K8/Phenom/...)?如果您对此问题提供答案(是/否),请同时指定用于确定答案的方法 - PDF文档查找,强力测试,数学证明或您用于确定答案的任何其他方法.
此问题涉及http://research.swtch.com/2010/02/off-to-races.html等问题
更新:
我在C中创建了一个可以在您的计算机上运行的简单测试程序.请在您的Phenom,Athlon,Bobcat,Core2,Atom,Sandy Bridge或您碰巧拥有的任何支持SSE2的CPU上编译并运行它.谢谢.
// Compile with:
// gcc -o a a.c -pthread -msse2 -std=c99 -Wall -O2
//
// Make sure you have at least two physical CPU cores or hyper-threading.
#include <pthread.h>
#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef int v4si __attribute__ ((vector_size (16)));
volatile v4si x;
unsigned n1[16] __attribute__((aligned(64)));
unsigned n2[16] __attribute__((aligned(64)));
void* thread1(void *arg) {
for (int i=0; i<100*1000*1000; i++) { …
Run Code Online (Sandbox Code Playgroud) 长话短说:我正在用C++开发一个计算密集型图像处理应用程序.它需要在从较大图像中提取的小像素块上计算图像变形的许多变体.该程序运行速度不如我想的那么快.分析(OProfile)显示变形/插值函数占用CPU时间的70%以上,因此尝试优化它似乎是显而易见的.
到目前为止,我正在使用OpenCV图像处理库完成任务:
// some parameters for the image warps (position, stretch, skew)
struct WarpParams;
void Image::get(const WarpParams ¶ms)
{
// fills matrices mapX_ and mapY_ with x and y coordinates of points to be
// inteprolated.
updateCoordMaps(params);
// perform interpolation to obtain pixels at point locations
// P(mapX_[i], mapY_[i]) based on the original data and put the
// result in pixels_. Use bicubic inteprolation.
cv::remap(image_->data(), pixels_, mapX_, mapY_, CV_INTER_CUBIC);
}
Run Code Online (Sandbox Code Playgroud)
我编写了自己的插值函数并将其放入测试工具中以确保在我进行实验时的正确性,并将其与旧的相比较.
我的功能运行得很慢,这是预料之中的.一般来说,这个想法是:
旧功能在我的Wolfdale Core2 Duo上的时间为25us.新的拿了587us(!).我急切地把我的巫师帽子打开并开始破解代码.我设法删除所有分支,省略一些重复计算,并将3个嵌套循环转换为坐标映射中的一个.这就是我想出的:
void …
Run Code Online (Sandbox Code Playgroud) 我有一个用C++编写的循环,它是为一个大整数数组的每个元素执行的.在循环内部,我屏蔽了整数的一些位,然后找到最小值和最大值.我听说如果我使用SSE指令进行这些操作,它将比使用按位AND和if-else条件写入的普通循环运行得快得多.我的问题是我应该参加这些SSE指令吗?此外,如果我的代码在不同的处理器上运行会发生什么?它仍然可以工作或这些指令是特定于处理器的吗?
我正在寻找英特尔数据表:英特尔®64和IA-32架构软件开发人员手册 ,我找不到它们之间的区别
在英特尔数据表中,我可以找到两个指令:
该指令可用于从128位存储器位置加载XMM寄存器,将XMM寄存器的内容存储到128位存储器位置,或在两个XMM寄存器之间移动数据.
唯一的区别是:
要将双四字移入或移出未对齐的存储单元,请使用MOVDQU指令.
和
要将打包的单精度浮点值移入或移出未对齐的内存位置,请使用MOVUPS指令.
但是我找不到两个不同指令的原因?
那么有人可以解释这个区别吗?
我正在阅读这份文件:http://software.intel.com/en-us/articles/interactive-ray-tracing
我偶然发现了这三行代码:
SIMD版本已经快了很多,但我们可以做得更好.英特尔为SSE2指令集添加了快速1/sqrt(x)函数.唯一的缺点是它的精度有限.我们需要精度,所以我们使用Newton-Rhapson来改进它:
__m128 nr = _mm_rsqrt_ps( x );
__m128 muls = _mm_mul_ps( _mm_mul_ps( x, nr ), nr );
result = _mm_mul_ps( _mm_mul_ps( half, nr ), _mm_sub_ps( three, muls ) );
Run Code Online (Sandbox Code Playgroud)
此代码假定存在名为"half"(四次0.5f)和变量"three"(四次3.0f)的__m128变量.
我知道如何使用牛顿拉夫森计算函数的零点,我知道如何使用它来计算一个数的平方根,但我看不出这些代码如何执行它.
有人可以向我解释一下吗?
这是我通常用于通过Visual Studio和GCC获得对齐内存的代码
inline void* aligned_malloc(size_t size, size_t align) {
void *result;
#ifdef _MSC_VER
result = _aligned_malloc(size, align);
#else
if(posix_memalign(&result, align, size)) result = 0;
#endif
return result;
}
inline void aligned_free(void *ptr) {
#ifdef _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
Run Code Online (Sandbox Code Playgroud)
这个代码一般是好的吗?我也见过人们用_mm_malloc
,_mm_free
.在大多数情况下,我想要对齐内存,使用SSE/AVX.我可以一般使用这些功能吗?它会使我的代码更简单.
最后,创建我自己的函数来对齐内存很容易(见下文).为什么会有这么多不同的常用函数来获得对齐的内存(其中许多只能在一个平台上运行)?
此代码执行16字节对齐.
float* array = (float*)malloc(SIZE*sizeof(float)+15);
// find the aligned position
// and use this pointer to read or write data into array
float* alignedArray = (float*)(((unsigned long)array + 15) & (~0x0F));
// dellocate memory …
Run Code Online (Sandbox Code Playgroud) 如果你有一个输入数组和一个输出数组,但是你只想写那些通过某个条件的元素,那么在AVX2中这样做最有效的方法是什么?
我在SSE看到它是这样做的:(来自:https://deplinenoise.files.wordpress.com/2015/03/gdc2015_afredriksson_simd.pdf)
__m128i LeftPack_SSSE3(__m128 mask, __m128 val)
{
// Move 4 sign bits of mask to 4-bit integer value.
int mask = _mm_movemask_ps(mask);
// Select shuffle control data
__m128i shuf_ctrl = _mm_load_si128(&shufmasks[mask]);
// Permute to move valid values to front of SIMD register
__m128i packed = _mm_shuffle_epi8(_mm_castps_si128(val), shuf_ctrl);
return packed;
}
Run Code Online (Sandbox Code Playgroud)
这对于4宽的SSE来说似乎很好,因此只需要16个入口LUT,但对于8宽的AVX,LUT变得非常大(256个条目,每个32个字节或8k).
我很惊讶AVX似乎没有简化此过程的指令,例如带有打包的蒙版存储.
我想通过稍微改变来计算左边设置的符号位数,你可以生成必要的排列表,然后调用_mm256_permutevar8x32_ps.但这也是我认为的一些指示......
有没有人知道用AVX2做这个的任何技巧?或者什么是最有效的方法?
以下是上述文件中左包装问题的说明:
谢谢
我有一些代码,最初是由MSVC工作人员给我的,我正试图让它在Clang上工作.这是我遇到麻烦的功能:
float vectorGetByIndex( __m128 V, unsigned int i )
{
assert( i <= 3 );
return V.m128_f32[i];
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误如下:
Member reference has base type '__m128' is not a structure or union.
Run Code Online (Sandbox Code Playgroud)
我环顾四周,发现Clang(也许是GCC)在将__m128视为结构或联合时遇到了问题.但是我还没有找到一个直接的答案,我怎么能得到这些价值.我已经尝试过使用下标运算符而无法做到这一点,我已经浏览了大量的SSE内在函数列表并且尚未找到合适的函数.
我想尝试使用SIMD指令编写atoi实现,包含在RapidJSON(C++ JSON 读 /写库)中.它目前在其他地方有一些SSE2和SSE4.2优化.
如果是速度增益,atoi
则可以并行执行多个结果.字符串最初来自JSON数据的缓冲区,因此多atoi函数将不得不进行任何所需的调配.
我想出的算法如下:
我的目标是x86和x86-64架构.
我知道AVX2支持三个操作数Fused Multiply-Add,所以我将能够执行Sum = Number*有效数字+和.
那是我到目前为止的地方.
我的算法是否正确?有没有更好的办法?
是否有使用任何SIMD指令集的atoi参考实现?