职业技术学院网站建设项目,公司网站备案是什么意思,舆情报告案例2022,临清网站建设公司Intel Intrinsics Guide
搞懂SSE 寄存器与指令数据细节 SSE指令集推出时#xff0c;Intel公司在Pentium III CPU中增加了8个128位的SSE指令专用寄存器#xff0c;称作XMM0到XMM7。这些XMM寄存器用于4个单精度浮点数运算的SIMD执行#xff0c;并可以与MMX整数运算或x87浮点运…Intel® Intrinsics Guide
搞懂SSE 寄存器与指令数据细节 SSE指令集推出时Intel公司在Pentium III CPU中增加了8个128位的SSE指令专用寄存器称作XMM0到XMM7。这些XMM寄存器用于4个单精度浮点数运算的SIMD执行并可以与MMX整数运算或x87浮点运算混合执行。 2001年在Pentium 4上引入了SSE2技术进一步扩展了指令集使得XMM寄存器上可以执行8/16/32位宽的整数SIMD运算或双精度浮点数的SIMD运算。对整型数据的支持使得所有的MMX指令都是多余的了同时也避免了占用浮点数寄存器。SSE2为了更好地利用高速寄存器还新增加了几条寄存指令允许程序员控制已经寄存过的数据。这使得 SIMD技术基本完善。 SSE3指令集扩展的指令包含寄存器的局部位之间的运算例如高位和低位之间的加减运算浮点数到整数的转换以及对超线程技术的支持。
AVX是Intel的SSE延伸架构把寄存器XMM 128bit提升至YMM 256bit以增加一倍的运算效率。 数据结构 由于通常没有内建的128bit和256bit数据类型SIMD指令使用自己构建的数据类型这些类型以union实现这些数据类型可以称作向量一般来说MMX指令是__m64 类型的数据SSE是__m128类型的数据等等 每一种类型从2个下划线开头接一个m然后是向量的位长度。如果向量类型是以d结束的那么向量里面是double类型的数字。如果没有后缀就代表向量只包含float类型的数字。整形的向量可以包含各种类型的整形数例如char,short,unsigned long long。也就是说__m256i可以包含32个char16个short类型8个int类型4个long类型。这些整形数可以是有符号类型也可以是无符号类型
内存对齐 为了方便CPU用指令对内存进行访问通常要求某种类型对象的地址必须是某个值K通常是2、4或8的倍数如果一个变量的内存地址正好位于它长度的整数倍我们就称他是自然对齐的。
通常对于各种类型的对齐规则如下
数组 按照基本数据类型对齐第一个对齐了后面的自然也就对齐了。 联合 按其包含的长度最大的数据类型对齐。 结构体 结构体中每个数据类型都要对齐
对于SIMD的内存对齐是指__m128等union在内存中存储时的存储方式。 对于各成员变量来说存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数各成员变量在存放的时候根据在结构中出现的顺序依次申请空间 同时按照上面的对齐方式调整位置 空缺的字节自动填充。 对于整个结构体来说为了确保结构的大小为结构的字节边界数(即该结构中占用最大的空间的类型的字节数)的倍数所以在为最后一个成员变量申请空间后还会根据需要自动填充空缺的字节。 intel官网
https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html
解决报错
SSE采用“接-化-发”原理
寄存器接收
__m128i _mm_loadu_si128 (__m128i const* mem_addr)
处理转化 __m128i _mm_cvtepu8_epi16 (__m128i a)
__m256i _mm256_sub_epi16 (__m256i a, __m256i b)
...... 发送出去
void _mm256_storeu_si256 (__m256i * mem_addr, __m256i a) 项目总结 大佬说这个正常情况下用一维的就可以了有必要的时候才用2维的 大致意思是 公司一般用一维就够用了因为二维的会多出来一个维度公司的电脑是8核的 使用二维会增大好多计算量。 我理解 90%的情况是一维的 yr:我们目前好像都是用一维的 我们一般都是对 row分割 . 理由大概率是这个吧 所以一般tbb对于大图像的提速会好一点 加速时会消耗内存以提高速度 消耗内存就是空间换时间 算法分为空间复杂度和时间复杂度一般在工作中时间要求更高可以改变算法逻辑必要情况下哪怕提高空间复杂度也要降低时间复杂度 并发算法都是压榨设备的性能特别是现在的多核处理器。但是如果设备性能不够高即使很高的并发也实现不了而且将串行修改成并行或者并发都是要额外付出时间的所以leader说没必要用二维度的range就是因为公司电脑性能带不动二维强行使用带不来较一维明显的效果还压榨设备性能也会造成硬件的加速老化。 实际项目中往往牺牲内存提升速度通过开辟更大的内存即扩大空间复杂度。来降低算法实现的时间复杂度 所以同样的效果其实可以有很多实现方式而且优劣分明。
加速算法主要就是在空间复杂度和时间复杂度上下文章
电脑提速从而减少浪费内存
1、tbb和OpenMP都是多线程的无法结合进行加速尝试结合后时间迸发
2、tbb加速比较实用的还是lambda表达式的形式
3、OpenMP使用需要配置VS属性
在项目上右键-属性-配置属性-C/C-语言-OpenMP支持选择“是”即可。提供指向 OpenMP API 中使用的构造的链接。
4、SSE支持的数据类型是4个32位共计128位浮点数集合就是C、C语言中的float[4]并且必须是以16位字节边界对齐的。因此这也给输入和输出带来了不少的麻烦实际上主要影响SSE发挥性能的就是不停地对数据进行复制以适用应它的数据格式。
5、用AVX指令集必须做好合适的IDE配置。
在C/C -代码生成的启用增强指令集里 使用注意事项
该代码段使用Intel SSE (Streaming SIMD Extensions) 指令集进行图像处理。通过看代码它似乎对图像中的每个像素执行一些操作具体地它似乎是对两张图像执行了某种差异检测。
以下是我观察到的一些问题及建议
拼写错误: m_offest 应该是 m_offset。在 if (filterPtr[c] - srcPtr[c] m_offest) 中确保变量名是正确的。
可能的内存对齐问题: 当使用 _mm_loadu_si128 时它从非对齐的内存加载数据。对于最佳性能如果您的数据是对齐的使用 _mm_load_si128 会更快。但这取决于 m_srcImage.ptrconst uchar(r) 返回的数据是否已经对齐。
越界访问: 在SSE循环中确保您不会越过图像的尾部。(m_srcImage.cols) - 32 可能导致您在最后几列中丢失一些像素。但在您的代码中之后的非SSE循环应该会处理这些只要确保这两个循环之间没有重叠或遗漏。
_x80 和 reg_offset 未定义: 代码中使用了 _x80 和 reg_offset但没有给出其定义或赋值。这可能只是提供的代码片段的一部分但确保这两个变量在上文中有正确的定义和初始化。
差异检测逻辑: SSE循环和非SSE循环似乎有不同的逻辑。在SSE部分您首先对像素值执行XOR操作并在减去之前比较它们。在非SSE部分您只是直接减去它们。这两者可能不完全等价除非 _x80 仅仅是一个将无符号字节转换为有符号字节的偏移量。
比较操作的逻辑: 在SSE部分您使用了 _mm_cmplt_epi8这会比较两个向量中的每个字节并返回一个掩码其中每个字节要么是 0xFF (如果a b)要么是 0x00。这可能与非SSE部分中的逻辑不完全匹配因为您在那里直接将值设置为 255 或 0。确保两者的逻辑是一致的。
总的来说除了这些问题和考虑点外代码似乎是为了性能优化而写的。确保在更改之后进行充分的测试以确保您的修改不会引入新的问题或性能下降。
SSE部分和小于部分差异防止
差异检测逻辑:
在使用SSE指令集进行图像处理时保持一致性非常重要。下面是一种方法可以使SSE循环和非SSE循环的逻辑保持一致。
差异检测逻辑的统一
定义_x80的用途: _x80 应该是一个常量其值是 128 (即 0x80 in hexadecimal)它用于将无符号整数转换为有符号整数反之亦然。这样可以使得原本的 0..255 范围的无符号字节变为 -128..127 的有符号字节。在非SSE循环中应用相同的转换: 为了使非SSE循环与SSE循环保持一致您需要在处理之前将无符号字节转换为有符号字节。
修改后的非SSE循环部分可以是 // 其他情况下C小于32的时候处理
for (; c m_srcImage.cols; c)
{
//if (filterPtr[c] - srcPtr[c] m_offest) //m_offest偏移量
// threshPtr[c] 255;
//else
// threshPtr[c] 0;
// 将像素值转换为有符号形式与SSE部分保持一致// 将像素值转换为有符号形式与SSE部分保持一致const char signed_src static_castchar(srcPtr[c] ^ 0x80);const char signed_filter static_castchar(filterPtr[c] ^ 0x80);// 使用有符号字节进行差值计算if (signed_filter - signed_src static_castchar(m_offset))threshPtr[c] 255;elsethreshPtr[c] 0;
}